string [线段树优化桶排]

Posted wang-hesong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了string [线段树优化桶排]相关的知识,希望对你有一定的参考价值。

题意大概是给你一个字符串,1e5次修改,每次给一个区间升序排列或降序排列,最后输出这个字符串;

其实是个挺裸的线段树优化题;但是我没有意识去结合桶排,扑该.....

首先 1.40分算法

O(NMlogN)

 1 inline void update(int k)
 2     for(int i=1;i<=26;++i)
 3         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
 4     
 5 
 6 
 7 void ud(int k,int l,int r,int L,int R)
 8     if(L<=l&&r<=R)return void();
 9     if(L<=mid)ud(ls,l,mid,L,R);
10     if(R>mid)ud(rs,mid+1,r,L,R);
11     update(k);
12

直接sort

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define val(x) (x-‘a‘+1)
 4 int s[100050],N,M;
 5 char S[100050];
 6 bool cmp1(int a,int b)return a<b;
 7 bool cmp0(int a,int b)return a>b;
 8 int main()
 9 
10     //freopen("da.in","r",stdin);
11    // freopen("ac.out","w",stdout);
12     scanf("%d%d",&N,&M);
13     scanf("%s",S+1);
14     for(int i=1;i<=N;++i)s[i]=val(S[i]);
15     for(int i=1,l,r,opt;i<=M;++i)
16         scanf("%d%d%d",&l,&r,&opt);
17         if(!opt)sort(s+l,s+r+1,cmp0);
18         else sort(s+l,s+r+1,cmp1);
19        // if(clock()>999900)break;
20     
21     char c;
22     for(int i=1;i<=N;++i)
23         c=s[i]+a-1;
24         printf("%c",c);
25     
26     printf("\n");
27 

其次 2.仍是40分算法:

其实也是出题人没良心,我们可以直接桶排,复杂度O(NM);起码降下了一个log,但还是40分;

代码就不提供了;

最后 3.100分算法:

思路:结合2.中的桶排思想,我们发现修改排序一次可以只有O(N)的复杂度,而N,M<=1e5,自然想到线段树优化桶排;

而这样想的裸想法的复杂度是O(MNlogN)氧化钙!跟暴力一样!

但是可以发现 你的数值N的值域是你的字母,那N就只有26啦;

最后O(MlogN*26)

分析一下  M是询问;  logN是线段树上的查询(合并桶而需查询你所修改的区域的桶来合成一个新的桶); 26是每次桶合并所需复杂度;

好,接下来,我们每次修改一个区间进行排序,就是把对应区间的桶合并成一个新桶,然后用这个新桶进行区间修改,但是注意,这个区间修改一定不要去真的O(N)区间赋值

那就成为了真正的O(NMlogN)了;

那怎么办?

我们可以打懒标记啊!别说你像我一样不会打标记......

那我们就可以标记哪个区间被修改了然后访问到再down一下,最后一遍dfs来一次全down统计答案对吧;

注意,这里down很长很长

 1 void down(int k)
 2     if(!tmp[k].lazy)return ;
 3     register int sz=len(ls),pl=0,pr=0;
 4     memset(tmp[ls].tong,0,sizeof(tmp[ls].tong));
 5     memset(tmp[rs].tong,0,sizeof(tmp[rs].tong));
 6     if(tmp[k].opt)
 7         for(int i=1;i<=26;++i)
 8             if(tmp[k].tong[i]<=sz)
 9             
10                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
11             
12             else 
13                 tmp[ls].tong[i]=sz;sz=i;break;
14             
15         
16         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
17         if(len(rs)==1&&tmp[rs].tong[sz]==1)pr=sz;
18         register int zs=len(rs)-tmp[rs].tong[sz];
19         for(int i=sz+1;i<=26;++i)
20             tmp[rs].tong[i]=tmp[k].tong[i];
21             zs-=tmp[k].tong[i];
22             if(!zs)break;
23         
24     
25     else 
26         for(int i=26;i>=1;--i)
27             if(tmp[k].tong[i]<=sz)
28             
29                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
30             
31             else 
32                 tmp[ls].tong[i]=sz;sz=i;break;
33             
34         
35         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
36         register int zs=len(rs)-tmp[rs].tong[sz];
37         for(int i=sz-1;i>=1;--i)
38             tmp[rs].tong[i]=tmp[k].tong[i];
39             zs-=tmp[k].tong[i];
40             if(!zs)break;
41         
42     
43     if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=1;
44     else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
45     if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=1;
46     else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
47     tmp[k].lazy=0;tmp[k].opt=0;
48 

当然我不像Deepin某一样缩行;

其实这里的down就是把你线段树上这个节点的两个儿子所对应区间的桶重新赋值的过程,当然赋值一次需要O(52);

Tip:

还有一点特别容易错的就是

记住每次把你对应修改的区间的桶合并后要立即修改对应区间的桶(区间修改):(这里lg这个vector存放的是你修改的区间的在线段树上的节点编号)

技术图片
 1 void exch(int opt)
 2     sort(lg.begin(),lg.end(),cmp);
 3     for(int i=0,sz,tt=1,ts=26;i<lg.size();++i)
 4         sz=len(lg[i]);
 5         memset(tmp[lg[i]].tong,0,sizeof(tmp[lg[i]].tong));
 6         if(opt)
 7             for(;tt<=26;++tt)
 8             if(sz>=ans[tt])
 9                 sz-=ans[tt];
10                 tmp[lg[i]].tong[tt]=ans[tt];
11             
12             else 
13                 tmp[lg[i]].tong[tt]=sz;
14                 ans[tt]-=sz;break;
15             
16             
17         
18         else 
19             for(;ts>=1;--ts)
20                         if(sz>=ans[ts])
21                             sz-=ans[ts];
22                             tmp[lg[i]].tong[ts]=ans[ts];
23                         
24                         else 
25                             tmp[lg[i]].tong[ts]=sz;
26                             ans[ts]-=sz;break;
27                         
28             
29         
30     
31 
区间修改

然后修改完后要立即把你这些修改的区间到根update一遍,毕竟你的懒标记只能维护儿子而不能维护父亲;

技术图片
 1 inline void update(int k)
 2     for(int i=1;i<=26;++i)
 3         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
 4     
 5 
 6 
 7 
 8 void ud(int k,int l,int r,int L,int R)
 9     if(L<=l&&r<=R)return void();
10     if(L<=mid)ud(ls,l,mid,L,R);
11     if(R>mid)ud(rs,mid+1,r,L,R);
12     update(k);
13 
update

然后附上代码

技术图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define val(x) (x-‘a‘+1)
  4 #define mid (l+r>>1)
  5 #define ls (k<<1)
  6 #define rs (k<<1|1)
  7 #define len(x) (tmp[x].r-tmp[x].l+1)
  8 int s[100050],N,M;
  9 char S[100050];
 10 struct node
 11    int l;int r;
 12    int tong[30];
 13    int lazy,lz,opt;
 14 tmp[100050<<3];
 15 int ans[30];
 16 vector<int>lg;
 17 
 18 inline void update(int k)
 19     for(int i=1;i<=26;++i)
 20         tmp[k].tong[i]=tmp[ls].tong[i]+tmp[rs].tong[i];
 21     
 22 
 23 
 24 void down(int k)
 25     if(!tmp[k].lazy)return ;
 26     register int sz=len(ls),pl=0,pr=0;
 27     memset(tmp[ls].tong,0,sizeof(tmp[ls].tong));
 28     memset(tmp[rs].tong,0,sizeof(tmp[rs].tong));
 29     if(tmp[k].opt)
 30         for(int i=1;i<=26;++i)
 31             if(tmp[k].tong[i]<=sz)
 32             
 33                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
 34            //     if(len(ls)==1&&tmp[ls].tong[i])pl=i;break;
 35             
 36             else 
 37                 tmp[ls].tong[i]=sz;sz=i;break;
 38             
 39         
 40         //for(int i=1;i<=sz-1;++i)tmp[rs].tong[i]=0;
 41         //for(int i=sz+1;i<=26;++i)tmp[ls].tong[i]=0;
 42         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
 43         if(len(rs)==1&&tmp[rs].tong[sz]==1)pr=sz;
 44         register int zs=len(rs)-tmp[rs].tong[sz];
 45         for(int i=sz+1;i<=26;++i)
 46             tmp[rs].tong[i]=tmp[k].tong[i];
 47             zs-=tmp[k].tong[i];
 48             if(!zs)break;
 49         //    if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
 50         
 51     
 52     else 
 53         for(int i=26;i>=1;--i)
 54             if(tmp[k].tong[i]<=sz)
 55             
 56                 tmp[ls].tong[i]=tmp[k].tong[i],sz-=tmp[k].tong[i];
 57                // if(len(ls)==1&&tmp[ls].tong[i])pl=i;break;
 58             
 59             else 
 60                 tmp[ls].tong[i]=sz;sz=i;break;
 61             
 62         
 63         //for(int i=26;i>=sz+1;--i)tmp[rs].tong[i]=0;
 64         //for(int i=1;i<=sz-1;++i)tmp[ls].tong[i]=0;
 65         tmp[rs].tong[sz]=tmp[k].tong[sz]-tmp[ls].tong[sz];
 66         //if(len(rs)==1&&tmp[rs].tong[sz]==1)pr=sz;
 67         register int zs=len(rs)-tmp[rs].tong[sz];
 68         for(int i=sz-1;i>=1;--i)
 69             tmp[rs].tong[i]=tmp[k].tong[i];
 70             zs-=tmp[k].tong[i];
 71             if(!zs)break;
 72           //  if(len(rs)==1&&tmp[rs].tong[i]&&!pr)pr=i;
 73         
 74     
 75     if(tmp[ls].l!=tmp[ls].r)tmp[ls].lazy=1;
 76     else tmp[ls].lz=pl;tmp[ls].opt=tmp[k].opt;
 77     if(tmp[rs].l!=tmp[rs].r)tmp[rs].lazy=1;
 78     else tmp[rs].lz=pr;tmp[rs].opt=tmp[k].opt;
 79     tmp[k].lazy=0;tmp[k].opt=0;
 80 
 81 
 82 inline void merge(int u,int opt)
 83     down(u);
 84     for(register int i=1;i<=26;++i)
 85         ans[i]+=tmp[u].tong[i];
 86     
 87     if(len(u)>1)tmp[u].lazy=1;lg.push_back(u);
 88     tmp[u].opt=opt;
 89 
 90 
 91 inline int zip(int k)
 92     //cout<<"laidao!"<<endl;
 93     for(int i=1;i<=26;++i)if(tmp[k].tong[i])return i;
 94 
 95 
 96 void find(int k,int l,int r)
 97     if(l==r)return s[l]=zip(k),void();
 98     down(k);
 99     find(ls,l,mid);
100     find(rs,mid+1,r);
101 
102 
103 void query(int k,int l,int r,int L,int R,int opt)
104     if(L<=l&&r<=R)return merge(k,opt),void();
105     down(k);
106     if(L<=mid)query(ls,l,mid,L,R,opt);
107     if(R>mid)query(rs,mid+1,r,L,R,opt);
108 
109 
110 void ud(int k,int l,int r,int L,int R)
111     if(L<=l&&r<=R)return void();
112     if(L<=mid)ud(ls,l,mid,L,R);
113     if(R>mid)ud(rs,mid+1,r,L,R);
114     update(k);
115 
116 
117 void building(int k,int l,int r)
118     tmp[k].l=l;tmp[k].r=r;
119     if(l==r)return  tmp[k].l=tmp[k].r=l,tmp[k].tong[s[l]]=1,tmp[k].lazy=tmp[k].opt=0,void();
120     building(ls,l,mid);building(rs,mid+1,r);
121     update(k);
122 
123 
124 bool cmp(int u,int v)return tmp[u].l<tmp[v].l;
125 
126 void exch(int opt)
127     sort(lg.begin(),lg.end(),cmp);
128     for(int i=0,sz,tt=1,ts=26;i<lg.size();++i)
129         sz=len(lg[i]);
130         memset(tmp[lg[i]].tong,0,sizeof(tmp[lg[i]].tong));
131         if(opt)
132             for(;tt<=26;++tt)
133             if(sz>=ans[tt])
134                 sz-=ans[tt];
135                 tmp[lg[i]].tong[tt]=ans[tt];
136             
137             else 
138                 tmp[lg[i]].tong[tt]=sz;
139                 ans[tt]-=sz;break;
140             
141             
142         
143         else 
144             for(;ts>=1;--ts)
145                         if(sz>=ans[ts])
146                             sz-=ans[ts];
147                             tmp[lg[i]].tong[ts]=ans[ts];
148                         
149                         else 
150                             tmp[lg[i]].tong[ts]=sz;
151                             ans[ts]-=sz;break;
152                         
153             
154         
155     
156 
157 int main()
158 
159     //freopen("da.in","r",stdin);
160     //freopen("te.out","w",stdout);
161     scanf("%d%d",&N,&M);
162     scanf("%s",S+1);
163     for(int i=1;i<=N;++i)s[i]=val(S[i]);
164     building(1,1,N);
165     for(int i=1,l,r,opt;i<=M;++i)
166         scanf("%d%d%d",&l,&r,&opt);
167         memset(ans,0,sizeof(ans));lg.clear();
168         query(1,1,N,l,r,opt);
169         exch(opt);
170         ud(1,1,N,l,r);
171     
172     find(1,1,N);
173     char c;
174     for(int i=1;i<=N;++i)
175         c=s[i]+a-1;
176         printf("%c",c);
177     
178     printf("\n");
179     //int ppx=‘P‘-‘a‘+1;
180     //cout<<"ppx="<<ppx<<endl;
181 
ac

 

以上是关于string [线段树优化桶排]的主要内容,如果未能解决你的问题,请参考以下文章

权值线段树离散化介绍 (+利用 线段树 求逆序对)

机房测试1:string(线段树)

解析·优化 ZKW线段树

模拟赛T2 线段树优化建图+tarjan+拓扑排序

CF786B Legacy[线段树优化建图]

降临(线段树优化dp)