1. 程式人生 > >【CodeForces】F. Letters Removing

【CodeForces】F. Letters Removing

blog ons hid nbsp 題意 style sin n) ret

【題目】F. Letters Removing

【題意】給定只含小寫字母、大寫字母和數字的字符串,每次給定一個範圍要求刪除[l,r]內的字符c(l和r具體位置隨刪除變動),求m次操作後的字符串。n<=2*10^5。

【算法】樹狀數組+平衡樹(set)

【題解】因為坐標是序列變動後的,動態坐標可以轉化為找到第l個存在的數字到第r個存在的數字之間的範圍。

將序列中存在記為1,刪除記為0,轉化為找前綴和恰好為l和r的位置,這是樹狀數組的經典操作,詳見這篇題解介紹的方法(簡單的排名功能)

找到l和r在原數組的位置後,接下來需要刪除。因為字符個數不多,對每個字符開一個set記錄位置,然後lower_bound後逐個刪除即可。

復雜度O(n log n)。

技術分享圖片
#include<cstdio>
#include<cstring>
#include<set>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=200010,M=62;
int n,m,a[maxn],c[maxn];
char S[maxn],SS[10];
set<int>s[63];
set<int>::iterator it,itt;
int read(){
    char c;int
s=0,t=1; while(!isdigit(c=getchar()))if(c==-)t=-1; do{s=s*10+c-0;}while(isdigit(c=getchar())); return s*t; } #define lowbit(x) (x&-x) void modify(int x){for(int i=x;i<=n;i+=lowbit(i))c[i]--;} int ask(int x){int as=0;for(int i=x;i>=1;i-=lowbit(i))as+=c[i];return as;} int find(int
x){ int num=0,p=0; for(int i=20;i>=0;i--)if(p+(1<<i)<=n&&num+c[p+(1<<i)]<x)num+=c[p+=(1<<i)]; return p+1; } int p(char c){ if(a<=c&&c<=z)return c-a+1; if(A<=c&&c<=Z)return c-A+27; return c-0+53; } int main(){ n=read();m=read(); scanf("%s",S+1); for(int i=1;i<=n;i++){ a[i]=p(S[i]); s[a[i]].insert(i); } for(int i=1;i<=n;i++)c[i+lowbit(i)]+=++c[i]; for(int i=1;i<=m;i++){ int l=find(read()),r=find(read()),x; scanf("%s",SS);x=p(SS[0]); it=s[x].lower_bound(l); while(it!=s[x].end()&&*it<=r)modify(*it),itt=it,it++,s[x].erase(itt); } for(int i=1;i<=n;i++)if(ask(i)-ask(i-1))printf("%c",S[i]); return 0; }
View Code

【CodeForces】F. Letters Removing