扩展莫队小总结(一) (树上/带修改莫队)

不要在意尴尬的标题

 

最裸的莫队大家都会吧,我就不多说了

那么这是一篇关于扩展莫队的小总结

 

莫队的经典应用:多次询问区间内不同元素数量

本文将以本问题为中心,坚持....

 

树上莫队

凡是能在序列上搞的问题就可以上树

问题变成询问某条树链上不同元素数量

把树变成序列?$dfs$序!

先对树处理出$dfs$序,每个节点都有一个入栈时间$st$和出栈时间$ed$。

加入现在有给出一条链的两个端点$x,y$,设他们的公共祖先是$F$,然后分情况讨论

(1)$x=F$或$y=F$

我们在$dfs$序里取出$[st_{F},st_{x/y}]$这一段,发现链上的元素都只出现了一次,不在链上的元素出现0次或2次!

我们像莫队一样搞一个插入函数,并记录树上每个节点被插入次数。奇数次代表插入,欧数次代表删除

(2)$x,y!=F$

假设$st_{x}<st_{y}$

我们在$dfs$序里取出$ed_{x},st_{y}$这一段,会发现除了$F$以外,链上的其他元素都被取出来了。

还是用同样的实现方法,最后统计答案时特判$F$的贡献即可

 

裸题:Count On a Tree 2

BZOJ上这题强制在线...

 

 

 

带修改莫队

怎么让莫队资瓷修改呢?

在最普通的莫队里,我们记录修改的左右端点l,r。

而修改涉及到先后顺序问题,所以要增加一维t,把修改时间记录下来

询问的排序方式为:左端点所在块作为第一关键字。右端点所在块作为第二关键字。修改时间作为第三关键字

 

如何实现呢?顺便证明一下时间复杂度

先假设块的大小是$S$,左右指针是$L,R$

(1)当左右指针不跨块移动时,时间戳是递增的,我们按时间依次处理询问或是修改就好

每次不跨块移动左右指针的最大时间是$O(S)$的。最多移动$O(n)$次。不跨块移动左右指针总时间复杂度是$O(Sn)$

如果修改的位置$\in[L,R]$,处理修改对答案的影响。

整个过程最多处理$O(n)$个修改操作。跨块移动总次数最多$O((\frac{n}{S})^{2})$。修改带来的总时间复杂度是$O((\frac{n}{S})^{2}n)$

(2)当左右指针跨块移动时,时间戳需要回溯到某个时刻,我们需要还原这些修改。

跨块移动左右指针的最大时间是$O(n)$的。最多移动$O((\frac{n}{S})^{2})$次。跨块移动左右指针总时间复杂度是$O((\frac{n}{S})^{2}n)$

每次回溯的次数最多是$O(n)$的。跨块移动总次数最多$O((\frac{n}{S})^{2})$。回溯带来的总时间复杂度是$O((\frac{n}{S})^{2}n)$

总时间复杂度约为$O((\frac{n}{S})^{2}n+Sn)$,S的最优解是$S=n^{\frac{2}{3}}$

 

裸题:BZOJ 2453 维护队列

写的有点丑,见谅qwq

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 10010
 6 #define M1 1000010
 7 using namespace std;
 8  
 9 template <typename _T> void read(_T &ret)
10 {
11     ret=0; _T fh=1; char c=getchar();
12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
14     ret=ret*fh;
15 }
16  
17 int n,Q,de;
18 int a[N1],pie[N1],bar[M1]; 
19  
20 struct MO{
21 int l,r,t,id;
22 friend bool operator < (const MO &s1,const MO &s2)
23 {
24     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
25     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
26     if(s1.t!=s2.t) return s1.t<s2.t;
27 }
28 }mo[N1];
29  
30 struct OP{ int x,t,w,pre; }op[N1]; 
31 int L,R,T,N,M,now,sum;
32  
33 void add(int i)
34 {
35     bar[a[i]]++;
36     if(bar[a[i]]==1) sum++;
37 }
38 void del(int i)
39 {
40     bar[a[i]]--;
41     if(bar[a[i]]==0) sum--;
42 }
43 void ret(int t)
44 {
45     while(op[now+1].t<=t && now<M)
46     {
47         now++;
48         if(L<=op[now].x && op[now].x<=R) del(op[now].x);
49         op[now].pre=a[op[now].x]; a[op[now].x]=op[now].w;
50         if(L<=op[now].x && op[now].x<=R) add(op[now].x);
51     }
52     while(op[now].t>t && now>0)
53     {
54         if(L<=op[now].x && op[now].x<=R) del(op[now].x);
55         a[op[now].x]=op[now].pre;
56         if(L<=op[now].x && op[now].x<=R) add(op[now].x);
57         now--;
58     }
59 }
60  
61 int ans[N1];
62 int main()
63 {
64     scanf("%d%d",&n,&Q);
65     int i,j,q,l,r,t,sq; char str[10];
66     for(i=1;i<=n;i++) read(a[i]);
67     for(q=1;q<=Q;q++)
68     {
69         scanf("%s",str);
70         if(str[0]=='Q'){
71             N++; read(mo[N].l); read(mo[N].r); mo[N].t=q; mo[N].id=N;
72         }else{
73             M++; read(op[M].x); read(op[M].w); op[M].t=q;
74         }
75     }
76     sq=(int)(pow(n,0.666666667));
77     for(i=1;i<=n;i++) pie[i]=(i-1)/sq+1;
78     sort(mo+1,mo+N+1);
79     for(q=1;q<=N;q++)
80     {
81         l=mo[q].l, r=mo[q].r; t=mo[q].t;
82         while(R<r) R++, add(R);
83         while(L>l) L--, add(L);
84         while(R>r) del(R), R--;
85         while(L<l) del(L), L++;
86         ret(t); 
87         ans[mo[q].id]=sum;
88     }
89     for(q=1;q<=N;q++) printf("%d\n",ans[q]); 
90     return 0;
91 }
View Code

 

 

 

带修改树上莫队

把上面两个算法结合一下就行啦

裸题:

BZOJ 4129 Haruna’s Breakfast

由于只有$n$个节点,所以可能对答案的产生贡献的范围只有$[0,n]$..

套个分块,记录每个块里有多少个元素出现过。

这样就是$O(1)$修改,$O(\sqrt{n})$查询啦

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 50005
  6 using namespace std;
  7  
  8 template <typename _T> void read(_T &ret)
  9 {
 10     ret=0; _T fh=1; char c=getchar();
 11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
 12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
 13     ret=ret*fh;
 14 }
 15 struct Edge{
 16 int to[N1*2],nxt[N1*2],head[N1],cte;
 17 void ae(int u,int v)
 18 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
 19 }e;
 20  
 21 int n,Q,de;
 22 int a[N1],st[N1],ed[N1],ord[N1*2],cur;
 23  
 24 namespace Tree{
 25  
 26 int fa[N1],dep[N1],sz[N1],son[N1],tp[N1];
 27 void dfs1(int x)
 28 {
 29     int j,v; sz[x]=1;
 30     for(j=e.head[x];j;j=e.nxt[j])
 31     {
 32         v=e.to[j]; if(v==fa[x]) continue;
 33         dep[v]=dep[x]+1; fa[v]=x; dfs1(v); 
 34         sz[x]+=sz[v]; son[x]=(sz[v]>sz[son[x]])?v:son[x];
 35     }
 36 }
 37 void dfs2(int x)
 38 {
 39     st[x]=++cur; ord[cur]=x;
 40     if(son[x]) tp[son[x]]=tp[x], dfs2(son[x]);
 41     int j,v;
 42     for(j=e.head[x];j;j=e.nxt[j])
 43     {
 44         v=e.to[j]; if(v==fa[x] || v==son[x]) continue;
 45         tp[v]=v; dfs2(v);
 46     }
 47     ed[x]=++cur; ord[cur]=x;
 48 }
 49 void init(){ dep[1]=1; dfs1(1); tp[1]=1; dfs2(1); }
 50 int LCA(int x,int y)
 51 {
 52     while(tp[x]!=tp[y])
 53     {
 54         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
 55         x=fa[tp[x]];
 56     }
 57     return dep[x]<dep[y]?x:y;
 58 }
 59  
 60 };
 61 using Tree::LCA; 
 62  
 63  
 64 namespace Captain_MO{
 65  
 66 int pie[N1*2],cnt[N1],vis[N1*2],num[N1],sum[N1],sq,now; 
 67  
 68 struct MO{
 69 int l,r,t,id,F;
 70 friend bool operator < (const MO &s1,const MO &s2)
 71 {
 72     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
 73     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
 74     if(s1.t!=s2.t) return s1.t<s2.t;
 75 }
 76 }mo[N1];
 77 struct OP{ int x,t,w,pre; }op[N1]; 
 78  
 79 void add(int i)
 80 {
 81     if(a[ord[i]]>n) return;
 82     if(cnt[ord[i]]&1){
 83         num[a[ord[i]]]--; 
 84         if(num[a[ord[i]]]==0) sum[a[ord[i]]/sq]--;
 85     }else{
 86         num[a[ord[i]]]++; 
 87         if(num[a[ord[i]]]==1) sum[a[ord[i]]/sq]++;
 88     }
 89     cnt[ord[i]]++;
 90 }
 91 int qmex()
 92 {
 93     int i,j;
 94     for(i=0;(i+1)*sq-1<=n;i++)
 95     {
 96         if(sum[i]==sq) continue;
 97         for(j=i*sq;j<(i+1)*sq;j++)
 98             if(!num[j]) return j;
 99     }
100     for(j=i*sq;j<=n;j++)
101         if(!num[j]) return j;
102 }
103  
104 int L,R,N,M;
105 void ret(int t)
106 {
107     int x;
108     while(op[now+1].t<=t && now<M)
109     {
110         now++; x=op[now].x;
111         if(L<=st[x] && st[x]<=R) add(st[x]);
112         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
113         op[now].pre=a[x]; a[x]=op[now].w;
114         if(L<=st[x] && st[x]<=R) add(st[x]);
115         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
116     }
117     while(op[now].t>t && now>0)
118     {
119         x=op[now].x;
120         if(L<=st[x] && st[x]<=R) add(st[x]);
121         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
122         a[x]=op[now].pre;
123         if(L<=st[x] && st[x]<=R) add(st[x]);
124         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
125         now--;
126     }
127 }
128  
129 int ans[N1];
130 void Main()
131 {
132     int i,j,x,y,q,fl,F,l,r,t;
133     for(j=1;j<=Q;j++)
134     {
135         read(fl); read(x); read(y);
136         if(fl){
137             N++; F=LCA(x,y); 
138             if(x==F){
139                 mo[N].l=st[x]; mo[N].r=st[y]; 
140             }else if(y==F){
141                 mo[N].l=st[y]; mo[N].r=st[x]; 
142             }else{
143                 if(st[x]>st[y]) swap(x,y);
144                 mo[N].l=ed[x]; mo[N].r=st[y]; mo[N].F=F;
145             }
146             mo[N].t=j; mo[N].id=N;
147         }else{ 
148             M++; op[M].x=x; op[M].w=y; op[M].t=j; 
149         }
150     }
151     sq=(int)(sqrt(cur));
152     t=(int)(pow(cur,0.6666666667)); 
153     for(i=1;i<=cur;i++) pie[i]=(i-1)/t+1;
154     sort(mo+1,mo+N+1);
155     L=1, R=1; add(1);
156     for(q=1;q<=N;q++)
157     {
158         l=mo[q].l; r=mo[q].r; t=mo[q].t;
159         while(R<r) R++, add(R);
160         while(L>l) L--, add(L);
161         while(R>r) add(R), R--; // del(R), R--; 
162         while(L<l) add(L), L++; // del(L), L++; 
163         ret(t);
164         if(mo[q].F) add(st[mo[q].F]);
165         ans[mo[q].id]=qmex();
166         if(mo[q].F) add(st[mo[q].F]);
167     }
168     for(q=1;q<=N;q++) printf("%d\n",ans[q]);
169 }
170  
171 };
172  
173 int main()
174 {
175     scanf("%d%d",&n,&Q);
176     int i,j,x,y; char str[10];
177     for(i=1;i<=n;i++) read(a[i]);
178     for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
179     Tree::init();
180     Captain_MO::Main();
181     return 0;
182 }
View Code

 

[WC2013]糖果公园

没什么好说的..记得开long long 

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 100010
  6 #define il inline 
  7 #define ll long long
  8 using namespace std;
  9  
 10 template <typename _T> void read(_T &ret)
 11 {
 12     ret=0; _T fh=1; char c=getchar();
 13     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
 14     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
 15     ret=ret*fh;
 16 }
 17  
 18 struct Edge{
 19 int to[N1*2],nxt[N1*2],head[N1],cte;
 20 void ae(int u,int v)
 21 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
 22 }e;
 23  
 24 int n,m,Q;
 25 int V[N1],W[N1],a[N1];
 26 int st[N1],ed[N1],ord[N1*2],cur;
 27  
 28  
 29 namespace Tree{
 30  
 31 int fa[N1],dep[N1],tp[N1],sz[N1],son[N1];
 32 void dfs1(int x)
 33 {
 34     int j,v; sz[x]=1;
 35     for(j=e.head[x];j;j=e.nxt[j])
 36     {
 37         v=e.to[j]; if(v==fa[x]) continue;
 38         dep[v]=dep[x]+1; fa[v]=x; dfs1(v);
 39         sz[x]+=sz[v]; son[x]=(sz[v]>sz[son[x]])?v:son[x];
 40     }
 41 }
 42 void dfs2(int x)
 43 {
 44     st[x]=++cur; ord[cur]=x;
 45     if(son[x]) tp[son[x]]=tp[x], dfs2(son[x]);
 46     int j,v;
 47     for(j=e.head[x];j;j=e.nxt[j])
 48     {
 49         v=e.to[j]; if(v==son[x] || v==fa[x]) continue;
 50         tp[v]=v; dfs2(v);
 51     }
 52     ed[x]=++cur; ord[cur]=x;
 53 }
 54 void init(){ dep[1]=1; dfs1(1); tp[1]=1; dfs2(1); }
 55 int LCA(int x,int y)
 56 {
 57     while(tp[x]!=tp[y])
 58     {
 59         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
 60         x=fa[tp[x]];
 61     }
 62     return dep[x]<dep[y]?x:y;
 63 }
 64  
 65 };
 66 using Tree::LCA;
 67  
 68  
 69 namespace Captain_Mo{
 70  
 71 int L,R,N,M,now;
 72 int pie[N1*2];
 73 struct MO{
 74 int l,r,t,id,F;
 75 friend bool operator < (const MO &s1,const MO &s2)
 76 {
 77     if(pie[s1.l]!=pie[s2.l]) return pie[s1.l]<pie[s2.l];
 78     if(pie[s1.r]!=pie[s2.r]) return pie[s1.r]<pie[s2.r];
 79     return s1.t<s2.t; 
 80 }
 81 }mo[N1];
 82 struct OP{ int x,w,t,pre; }op[N1];
 83  
 84 int cnt[N1],num[N1]; ll sum;
 85 il void add(int i) 
 86 {
 87     int x=ord[i];
 88     if(cnt[x]&1){
 89         sum-=1ll*V[a[x]]*W[num[a[x]]];
 90         num[a[x]]--;
 91     }else{
 92         num[a[x]]++;
 93         sum+=1ll*V[a[x]]*W[num[a[x]]];
 94     }
 95     cnt[x]++;
 96 }
 97 void ret(int t)
 98 {
 99     int x;
100     while(op[now+1].t<=t && now<M)
101     {
102         now++; x=op[now].x;
103         if(L<=st[x] && st[x]<=R) add(st[x]);
104         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
105         op[now].pre=a[x]; a[x]=op[now].w;
106         if(L<=st[x] && st[x]<=R) add(st[x]);
107         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
108     }
109     while(op[now].t>t && now>0)
110     {
111         x=op[now].x;
112         if(L<=st[x] && st[x]<=R) add(st[x]);
113         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
114         a[x]=op[now].pre;
115         if(L<=st[x] && st[x]<=R) add(st[x]);
116         if(L<=ed[x] && ed[x]<=R) add(ed[x]);
117         now--;
118     }
119 }
120  
121 ll ans[N1];
122 void Main()
123 {
124     int i,j,q,fl,x,y,F,l,r,t;
125     for(j=1;j<=Q;j++)
126     {
127         read(fl); read(x); read(y);
128         if(fl){
129             N++; F=LCA(x,y);
130             if(x==F){
131                 mo[N].l=st[x]; mo[N].r=st[y]; 
132             }else if(y==F){
133                 mo[N].l=st[y]; mo[N].r=st[x]; 
134             }else{
135                 if(st[x]>st[y]) swap(x,y);
136                 mo[N].l=ed[x]; mo[N].r=st[y]; mo[N].F=F;
137             }
138             mo[N].t=j; mo[N].id=N;
139         }else{
140             M++; op[M].x=x; op[M].w=y; op[M].t=j;  
141         }
142     }
143     t=(int)(pow(cur,0.666666667));
144     for(i=1;i<=cur;i++) pie[i]=(i-1)/t+1;
145     sort(mo+1,mo+N+1);
146     L=1, R=1; add(1);
147     for(q=1;q<=N;q++)
148     {
149         l=mo[q].l; r=mo[q].r; t=mo[q].t;
150         while(R<r) R++, add(R);
151         while(L>l) L--, add(L);
152         while(R>r) add(R), R--;
153         while(L<l) add(L), L++;
154         ret(t);
155         if(mo[q].F) add(st[mo[q].F]);
156         ans[mo[q].id]=sum;
157         if(mo[q].F) add(st[mo[q].F]);
158     }
159     for(q=1;q<=N;q++) printf("%lld\n",ans[q]);
160 }
161  
162 };
163  
164 int main()
165 {
166     int i,j,x,y;
167     scanf("%d%d%d",&n,&m,&Q);
168     for(i=1;i<=m;i++) read(V[i]); 
169     for(i=1;i<=n;i++) read(W[i]); 
170     for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
171     for(i=1;i<=n;i++) read(a[i]);
172     Tree::init();
173     Captain_Mo::Main();
174     return 0;
175 }
176 
View Code

 

posted @ 2019-03-20 23:14  guapisolo  阅读(243)  评论(0编辑  收藏  举报