JZOJ P5829 string 线段树

*题意:2个操作,1:[l,r]升序排序,2:[l,r]降序排序,最后输出序列

*线段树维护:[l,r]区间的字母是什么(必须完全覆盖),这样我们求字母个数的时候就等于(r-l+1)

*和普通线段树的区别:

1.建树的pushup:当左区间和右区间都是同一个字母,当前区间也是同一个字母

il int rs(int x){return x<<1|1;}
il void pushup(int x){
    if (tree[ls(x)].num==tree[rs(x)].num) tree[x].num=tree[ls(x)].num;
}

2.修改和查询的pushdown:下传之后因为排序,字母不在原来的位置,所以要清零

il void pushdown(int x){
    if (tree[x].num) tree[ls(x)].num=tree[x].num,tree[rs(x)].num=tree[x].num,tree[x].num=0;
}

最后输出的时候我们查询[i,i]这个单位区间,哪个字母的个数为1,就输出,记得清零

完整代码,会线段树的看代码应该会更清晰:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #define il inline
 6 using namespace std;
 7 const int maxn=1e6;
 8 int n,m,l,r,mark,f[30];
 9 char a[maxn];
10 struct node{
11     int num;
12 }tree[4*maxn];
13 il int ls(int x){return x<<1;}
14 il int rs(int x){return x<<1|1;}
15 il void pushup(int x){
16     if (tree[ls(x)].num==tree[rs(x)].num) tree[x].num=tree[ls(x)].num;
17 }
18 il void build(int x,int l,int r){
19     if (l==r){int pos=a[l]-'a'+1;tree[x].num=pos;return;}
20     int mid=(l+r)>>1;
21     build(ls(x),l,mid); build(rs(x),mid+1,r);
22     pushup(x);
23 }
24 il void pushdown(int x){
25     if (tree[x].num) tree[ls(x)].num=tree[x].num,tree[rs(x)].num=tree[x].num,tree[x].num=0;
26 }
27 il void query(int x,int l,int r,int nl,int nr){
28     if (nl<=l&&r<=nr&&tree[x].num!=0){f[tree[x].num]+=l-r+1;return;}
29     int mid=(l+r)>>1;
30     pushdown(x);
31     if (nl<=mid) query(ls(x),l,mid,nl,nr);
32     if (nr>mid) query(rs(x),mid+1,r,nl,nr);
33 }
34 il void update(int x,int l,int r,int nl,int nr,int i){
35 //    cout<<1<<endl;
36     if (nl<=l&&r<=nr||tree[x].num==i){tree[x].num=i;return;}
37     int mid=(l+r)>>1;
38     pushdown(x);
39     if (nl<=mid) update(ls(x),l,mid,nl,nr,i);
40     if (nr>mid) update(rs(x),mid+1,r,nl,nr,i);
41     pushup(x);
42 }
43 int main(){
44     scanf ("%d%d",&n,&m);
45     getchar();
46     for (int i = 1;i <= n;i++) scanf ("%c",&a[i]);
47     build(1,1,n); 
48     for (int i = 1;i <= m;i++){
49         memset(f,0,sizeof(f));
50         scanf ("%d%d%d",&l,&r,&mark);
51         query(1,1,n,l,r);
52         if (mark){
53             for (int i = 1;i <= 26;i++){
54                 if (f[i]) update(1,1,n,l,l+f[i]-1,i),l=l+f[i];
55             }
56         }
57         else {
58             for (int i = 26;i >= 1;i--){
59                 if (f[i]) update(1,1,n,l,l+f[i]-1,i),l=l+f[i];
60             }
61         }
62     }
63     for (int i = 1;i <= n;i++){
64         for (int j = 1;j <= 26;j++){
65             memset(f,0,sizeof(f));
66             query(1,1,n,i,i);
67             if (f[j]){char tmp='a'+j-1;cout<<tmp;break;}
68         }
69     }
70     return 0;
71     
72 }

 

posted @ 2020-08-31 19:43  小又又  阅读(100)  评论(0编辑  收藏  举报