题意:给你一个长度为n的字符串,然后进行m次删除操作,每次删除区间[l,r]内的某个字符,删除后并且将字符串往前补位,求删除完之后的字符串。
题解:先开80个set 将每个字符对应的下标存入空间, 然后每次删除了一个字符之后就将字符串的相应位置改成一个不会产生干扰的字符(我这里使用的是'.')。 并且在线段树的相应位置标记一下。然后每次删除时候的左右区间就用2分区查找。
找到位置pos 使得 [1,pos]的值等于 pos - l, 这样就可以找到相应的区间了。原因, [1,pos]的值代表着区间[1,pos]内被删除的元素个数是多少。 pos - 向左移动的数目([1,pos]) 就是在进行前面删除操作之后并往前补位的位置了。
1 #include<set> 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 const int N = 2e5+10; 8 int n, m; 9 int tree[N<<2]; 10 string str, tmp; 11 set<int> G[80]; 12 void PushUp(int rt) 13 { 14 tree[rt] = tree[rt<<1|1] + tree[rt<<1]; 15 } 16 void Revise(int L, int l, int r, int rt) 17 { 18 if(l == r) 19 { 20 tree[rt]++; 21 return ; 22 } 23 int m = l+r >> 1; 24 if(L <= m) Revise(L,lson); 25 else Revise(L,rson); 26 PushUp(rt); 27 } 28 int Query(int L, int R, int l, int r, int rt) 29 { 30 if(L <= l && r <= R) 31 return tree[rt]; 32 int m = l+r >> 1; 33 int ret = 0; 34 if(L <=m) ret += Query(L,R,lson); 35 if(m < R) ret+= Query(L,R,rson); 36 return ret; 37 } 38 int Find_pos(int pos) 39 { 40 int l = pos, r = n; 41 while(l <= r) 42 { 43 int m = l+r >> 1; 44 int num = Query(1,m,1,n,1); 45 if(m == num + pos && str[m] != '.') 46 { 47 return m; 48 } 49 else if(m < num+ pos) l = m+1; 50 else r = m - 1; 51 } 52 } 53 int main() 54 { 55 ios::sync_with_stdio(false); 56 cin.tie(0); 57 cout.tie(0); 58 cin >> n >> m; 59 cin >> str; 60 set<int>::iterator it; 61 str = "#"+str;//将字符串往右整体移动一位 62 for(int i = 1; i <= n; i++) 63 G[str[i]-'0'].insert(i);//将对应的位置分别存到对应的set 64 int l, r; 65 while(m--) 66 { 67 cin >> l >> r >> tmp; 68 if(l + tree[1] > n) continue; //如果区间左端点大于有效长度 69 if(l == r) l = r = Find_pos(l); //那么就表示不用进行删除操作了 70 else { 71 l = Find_pos(l); 72 if(r + tree[1] > n) r = n; 73 else r = Find_pos(r); 74 } 75 int pos =(int)tmp[0] - '0'; 76 it = G[pos].begin(); 77 while(it != G[pos].end()) 78 { 79 int index = *it; 80 if(index >= l && index <= r) 81 { 82 Revise(index,1,n,1); 83 str[index] = '.'; 84 it = G[pos].erase(it); 85 } 86 else it++; 87 if(index > r) break; 88 } 89 } 90 for(int i = 1; i <= n; i++) 91 { 92 if(str[i] != '.') 93 cout << str[i]; 94 } 95 cout << endl; 96 return 0; 97 }
树状数组代码:
1 #include<set> 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 const int N = 2e5+10; 6 int n, m; 7 int tree[N]; 8 string str, tmp; 9 set<int> G[80]; 10 int lowbit(int x) 11 { 12 return x&(-x); 13 } 14 void Add(int x) 15 { 16 while(x <= n) 17 { 18 tree[x]++; 19 x += lowbit(x); 20 } 21 } 22 int Query(int x) 23 { 24 int ret = 0; 25 while(x > 0) 26 { 27 ret += tree[x]; 28 x -= lowbit(x); 29 } 30 return ret; 31 } 32 int Find_pos(int pos) 33 { 34 int l = pos, r = n; 35 while(l <= r) 36 { 37 int m = l+r >> 1; 38 int num = Query(m); 39 if(m == num + pos && str[m] != '.') 40 { 41 return m; 42 } 43 else if(m < num+ pos) l = m+1; 44 else r = m - 1; 45 } 46 } 47 int main() 48 { 49 ios::sync_with_stdio(false); 50 cin.tie(0); 51 cout.tie(0); 52 cin >> n >> m; 53 cin >> str; 54 set<int>::iterator it; 55 str = "#"+str;//将字符串往右整体移动一位 56 for(int i = 1; i <= n; i++) 57 G[str[i]-'0'].insert(i);//将对应的位置分别存到对应的set 58 int l, r; 59 while(m--) 60 { 61 cin >> l >> r >> tmp; 62 if(l + tree[1] > n) continue; //如果区间左端点大于有效长度 63 if(l == r) l = r = Find_pos(l);//那么就表示不用进行删除操作了 64 else 65 { 66 l = Find_pos(l); 67 if(r + tree[1] > n) r = n; 68 else r = Find_pos(r); 69 } 70 71 int pos = tmp[0] - '0'; 72 it = G[pos].begin(); 73 while(it != G[pos].end()) 74 { 75 int index = *it; 76 if(index >= l && index <= r) 77 { 78 Add(index); 79 str[index] = '.'; 80 it = G[pos].erase(it); 81 } 82 else it++; 83 if(index > r) break; 84 } 85 } 86 for(int i = 1; i <= n; i++) 87 { 88 if(str[i] != '.') 89 cout << str[i]; 90 } 91 cout << endl; 92 return 0; 93 }