题目描述:
Description
This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k = 1 or in non-increasing order if k = 0.
Output the final string after applying the queries.
Input
The first line will contain two integers n, q (1 ≤ n ≤ 105, 0 ≤ q ≤ 50 000), the length of the string and the number of queries respectively.
Next line contains a string S itself. It contains only lowercase English letters.
Next q lines will contain three integers each i, j, k (1 ≤ i ≤ j ≤ n, ).
Output
Output one line, the string S after applying the queries.
Sample Input
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
10 1
agjucbvdfk
1 10 1
Sample Output
cbcaaaabdd
abcdfgjkuv
思路:
题目的意思是,给定一个字符串,有q个询问,要把区间[l,r]的字符根据k的值升序(k=1),或降序(k=0)改变。
因为字母集有26个字母,就可以建立27棵线段树分别维护区间上每个字母出现的次数,一般地,第i棵线段树维护字母i-1+'a'的数目。
维护字母在区间上出现的次数有什么用?想想我们要做的事情,就是把区间[l,r]上的排一个序,字母集有限,想到计数排序,用一个27大小(0不存)的cnt数组,cnt[i]记录字母i出现的次数
如果k是1,则下标从1开始,如果对应那一项不为0,说明区间这个位置要被覆盖成i,就直接覆盖掉原来的线段树对应区间[l,r]上记录的字母i出现的次数,注意这里是直接覆盖,而不是累加,所以要修改线段树模板的区间和的upgrade函数的sum[a][r]+=改为sum[a][r]=,(a表示字母a对应的线段树)对应的懒标记也改为=。
一开始由于循环写的有点长(值代码长度),把计数的变量写叉了,有因为上面没有注意是最直接覆盖,一直出现out of bound错误,一开始还莫名其妙,搞了一个上午一直到晚上才知道写错了(╯‵□′)╯︵┻━┻,bug真好写,改是真难。
一开始写得麻烦了,比如把区间修改成字母a,然后我还在后面有把在这个区间上的,原来的对应的字母对应的线段树,一个位置一个位置的修改,然后提交,超时。。。
咋办嘞?原来只要在开始输入l,r那会统计每个字母在这个区间上出现次数后,紧接着立马删掉原来的数据(区间上的数据全置0),这么一改,好家伙,连样例都过不了了-_-||
找了半天,然后联想到这题的直接覆盖的不同寻常之处,也就是不同于区间和,才发现懒标记我标的有问题,没有懒标记我标0,懒标记为0(区间清零要用的)的还是0,那我在pushdown的时候怎么区分这两种情况呢?
咋办?标奇偶!神奇,覆盖的标记是1,清零的标记是2,没有标记的是0,这样就可以区分,那我咋使用呢?lz%2就行,1就是1,2就是0,可以正常使用了。
这题思路清晰,就是要注意细节,果然还是我太菜了。。
知识点:线段树的覆盖(自编题目)
代码:(开了氧气上瘾了)(注释依稀可见我超时的地方)
1 #include <iostream> 2 #include <cstring> 3 #include <memory.h> 4 #define max_n 100005 5 using namespace std; 6 char s[max_n]; 7 int sum[27][max_n<<2]; 8 int lz[27][max_n<<2]; 9 int cnt[27]; 10 int n; 11 int q; 12 int k; 13 void pushup(int a,int r) 14 { 15 sum[a][r] = sum[a][r<<1]+sum[a][r<<1|1]; 16 } 17 void build(int a,int r,int lc,int rc) 18 { 19 if(lc==rc) 20 { 21 if(a==s[lc]-'a'+1) 22 sum[a][r] = 1; 23 lz[a][r] = 0; 24 return; 25 } 26 int mid = (lc+rc)>>1; 27 build(a,r<<1,lc,mid); 28 build(a,r<<1|1,mid+1,rc); 29 pushup(a,r); 30 } 31 void pushdown(int a,int r,int ln,int rn) 32 { 33 if(lz[a][r]) 34 { 35 //cout << "r" << r << endl; 36 sum[a][r<<1] = ln*(lz[a][r]%2);//注意这里的改变 37 sum[a][r<<1|1] = rn*(lz[a][r]%2);//还有这里 38 lz[a][r<<1] = lz[a][r]; 39 lz[a][r<<1|1] = lz[a][r]; 40 lz[a][r] = 0; 41 } 42 } 43 void upgrade(int a,int r,int L,int R,int lc,int rc,int val) 44 { 45 if(L<=lc&&rc<=R) 46 { 47 sum[a][r] = (rc-lc+1)*(val%2);//这里,这里! 48 lz[a][r] = val;//直接覆盖就是等于哦 49 return; 50 } 51 int mid = (lc+rc)>>1; 52 pushdown(a,r,mid-lc+1,rc-mid); 53 if(L<=mid) upgrade(a,r<<1,L,R,lc,mid,val); 54 if(mid<R) upgrade(a,r<<1|1,L,R,mid+1,rc,val); 55 pushup(a,r); 56 } 57 int query(int a,int r,int L,int R,int lc,int rc) 58 { 59 if(L<=lc&&rc<=R) 60 { 61 return sum[a][r]; 62 } 63 int mid = (lc+rc)>>1; 64 pushdown(a,r,mid-lc+1,rc-mid); 65 int res = 0; 66 if(L<=mid) res += query(a,r<<1,L,R,lc,mid); 67 if(mid<R) res += query(a,r<<1|1,L,R,mid+1,rc); 68 return res; 69 } 70 #pragma optimize(2) 71 int main() 72 { 73 cin >> n >> q; 74 for(int i = 1;i<=n;i++) 75 { 76 cin >> s[i]; 77 } 78 for(int i = 1;i<=26;i++) 79 { 80 build(i,1,1,n); 81 } 82 int l,r,k; 83 for(int i=0;i<q;i++) 84 { 85 cin >> l >> r >> k; 86 for(int j = 1;j<=26;j++) 87 { 88 cnt[j] = query(j,1,l,r,1,n); 89 upgrade(j,1,l,r,1,n,2);//直接清零 90 } 91 if(k==1) 92 { 93 int lp = l; 94 for(int p = 1; p<=26; p++) 95 { 96 if(cnt[p]) 97 { 98 char ch =p+'a'-1; 99 //cout << ch << ":" << cnt[p] << endl; 100 upgrade(p,1,lp,lp+cnt[p]-1,1,n,1); 101 lp = lp+cnt[p]; 102 /*for(int j = 0; j<cnt[p];j++) 103 { 104 upgrade(s[lp]-'a'+1,1,lp,lp,1,n,-1); 105 s[lp]=p+'a'-1; 106 lp++; 107 }*/ 108 } 109 } 110 /*for(int i = 1; i<=n; i++) 111 { 112 cout << s[i]; 113 } 114 cout << endl;*/ 115 } 116 else 117 { 118 int lp = l; 119 for(int p = 26; p>=1; p--) 120 { 121 if(cnt[p]) 122 { 123 char ch = p+'a'-1; 124 //cout << ch << ":" << cnt[p] << endl; 125 upgrade(p,1,lp,lp+cnt[p]-1,1,n,1); 126 lp = lp+cnt[p]; 127 /*for(int j = 0; j<cnt[p];j++) 128 { 129 upgrade(s[lp]-'a'+1,1,lp,lp,1,n,-1); 130 s[lp] = p+'a'-1; 131 lp++; 132 }*/ 133 134 } 135 } 136 /*for(int i = 1; i<=n; i++) 137 { 138 cout << s[i]; 139 } 140 cout << endl;*/ 141 } 142 } 143 for(int i = 1;i<=n;i++) 144 { 145 for(int j = 1;j<27;j++) 146 { 147 cnt[j] = query(j,1,i,i,1,n); 148 if(cnt[j]) 149 { 150 char ch = j-1+'a'; 151 cout << ch; 152 } 153 } 154 } 155 cout << endl; 156 return 0; 157 }