[线段树] Jzoj P5829 string
题解
- 可以建一棵线段树
- 把各个叶子节点就是对应字母的值
- 然后对于一个节点,如果其两个子节点的数值相同,那么它自己也附上相同的值
- 更改时如果区间不完全重合,那么就需要把其子孩子附上它的值
- 然后对于每一次操作,求其区间内各个字母的次数
- 然后按照要求从a-z或从z-a循环,依次替换线段树中的位置
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 struct edge{int l,r,v;}tree[400010]; 7 char s[100010]; 8 int n,m,f[30]; 9 void build(int l,int r,int d) 10 { 11 tree[d].l=l,tree[d].r=r; 12 if (l==r) 13 { 14 tree[d].v=s[l]-'a'+1; 15 return; 16 } 17 int mid=(l+r)/2; 18 build(l,mid,d*2),build(mid+1,r,d*2+1); 19 if (tree[d*2].v==tree[d*2+1].v) tree[d].v=tree[d*2].v; 20 } 21 void getnum(int l,int r,int d) 22 { 23 if (tree[d].l>=l&&tree[d].r<=r&&tree[d].v!=0) 24 { 25 f[tree[d].v]+=tree[d].r-tree[d].l+1; 26 return; 27 } 28 if (tree[d].v) tree[d*2].v=tree[d].v,tree[d*2+1].v=tree[d].v; 29 int mid=(tree[d].l+tree[d].r)/2; 30 if (mid>=l) getnum(l,r,d*2); 31 if (mid<r) getnum(l,r,d*2+1); 32 } 33 void change(int l,int r,int d,int x) 34 { 35 if (tree[d].l>=l&&tree[d].r<=r||tree[d].v==x) 36 { 37 tree[d].v=x; 38 return; 39 } 40 if (tree[d].v) tree[d*2].v=tree[d].v,tree[d*2+1].v=tree[d].v,tree[d].v=0; 41 int mid=(tree[d].l+tree[d].r)/2; 42 if (l<=mid) change(l,r,d*2,x); 43 if (mid<r) change(l,r,d*2+1,x); 44 if (tree[d*2].v==tree[d*2+1].v) tree[d].v=tree[d*2].v; 45 } 46 void out(int d) 47 { 48 if (tree[d].v) 49 { 50 for (int i=1;i<=tree[d].r-tree[d].l+1;i++) printf("%c",tree[d].v+'a'-1); 51 return; 52 } 53 out(d*2),out(d*2+1); 54 } 55 int main() 56 { 57 freopen("string.in","r",stdin); 58 freopen("string.out","w",stdout); 59 scanf("%d%d",&n,&m); 60 scanf("%s",s+1); 61 build(1,n,1); 62 for (int j=1;j<=m;j++) 63 { 64 int l,r,x; 65 scanf("%d%d%d",&l,&r,&x); 66 memset(f,0,sizeof(f)); 67 getnum(l,r,1); 68 if (x==1) 69 for (int i=1;i<=26;i++) 70 { 71 if (f[i]) change(l,l+f[i]-1,1,i),l=l+f[i]; 72 } 73 else 74 for (int i=26;i>=1;i--) 75 { 76 if (f[i]) change(l,l+f[i]-1,1,i),l=l+f[i]; 77 } 78 } 79 out(1); 80 return 0; 81 }