不要在意尴尬的标题
最裸的莫队大家都会吧,我就不多说了
那么这是一篇关于扩展莫队的小总结
莫队的经典应用:多次询问区间内不同元素数量
本文将以本问题为中心,坚持....
树上莫队
凡是能在序列上搞的问题就可以上树
问题变成询问某条树链上不同元素数量
把树变成序列?$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$的贡献即可
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}}$
写的有点丑,见谅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 ",ans[q]); 90 return 0; 91 }
带修改树上莫队
把上面两个算法结合一下就行啦
裸题:
由于只有$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 ",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 }
没什么好说的..记得开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 ",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