树上莫队
听说树上莫队只能搞子树询问?
http://codeforces.com/blog/entry/43230
这篇运用了一个奇技淫巧把它扩展到了路径询问。现在主要就解(fan)释(yi)一下那篇博客。
A. 子树树上莫队
现在有一棵树,有n个节点,节点有点权,每次询问一个子树内的不重复数个数。
1<=n,q<=10^5,1<=点权<=10^9。
这个题显然比较trivial嘛...先把点权离散一下,然后一遍dfs搞出dfs序,那么一个子树就对应dfs序上一段,所以我们就可以在dfs序上莫队,开一个数组记一下每个数的出现次数。
B. 路径树上莫队
现在有一棵树,有n个节点,节点有点权,每次询问一条路径上的不重复数个数。
1<=n,q<=10^5,1<=点权<=10^9。
莫队用不了了?我们重新定义一个dfs序!
我们在开始访问和结束访问一个点的时候都记一下时间戳,我们设开始访问的时间为st,结束访问的时间为ed。
我们假设要询问一条路径a-b,设lca为p=lca(a,b)。不妨设st[a]<=st[b](否则交换一下)。
当p=a时,这应该是一个比较简单的情形:a-b是一段父子链。
我们考虑这个新dfs序上[st[a],st[b]]的点,我们可以发现,a-b上的点被算了一遍,其他点都被算了2遍或0遍!那么我们统计的时候注意一下就可以了。
当p≠a时,我们也要一样统计[ed[a],st[b]]的点(从ed[a]开始为保证a不会被排除掉),但是这回lca会被重复统计,所以要另外算一下。
这题就是spoj上的COT2~
(其实并不是很好写啊qaq)
//By zzq #include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <math.h> #include <set> #include <map> using namespace std; #define SZ 666666 #define P 20 int n,m,a[SZ],fst[SZ],vb[SZ],nxt[SZ],as[SZ],M=0,fa[SZ]; void ad_de(int a,int b) {++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b;} void adde(int a,int b) {ad_de(a,b); ad_de(b,a);} int cc=0,st[SZ],ed[SZ],dfx[SZ]; void dfs(int x) { st[x]=++cc; dfx[cc]=x; for(int e=fst[x];e;e=nxt[e]) { int b=vb[e]; if(b==fa[x]) continue; fa[b]=x; dfs(b); } ed[x]=++cc; dfx[cc]=x; } typedef pair<int,int> pii; int cc_=0,app[SZ],dep[SZ],lo2[SZ]; pii pp[SZ],minn[SZ][P]; void dfs_(int x) { ++cc_; app[x]=cc_; pp[cc_]=pii(dep[x],x); for(int e=fst[x];e;e=nxt[e]) { int b=vb[e]; if(b==fa[x]) continue; dep[b]=dep[x]+1; dfs_(b); pp[++cc_]=pii(dep[x],x); } } void build() { for(int i=1;i<=cc_;i++) minn[i][0]=pp[i]; for(int i=1;i<=cc_;i++) { int g=0; while((1<<g)<=i) ++g; lo2[i]=g-1; } for(int p=1;p<P;p++) { for(int i=1;i<=cc_;i++) { if(i+(1<<p)-1>cc_) break; minn[i][p]=min(minn[i][p-1],minn[i+(1<<(p-1))][p-1]); } } } int lca(int a,int b) { a=app[a]; b=app[b]; if(a>b) swap(a,b); int l2=lo2[b-a+1]; return min(minn[a][l2],minn[b-(1<<l2)+1][l2]).second; } int bs,qn=0; struct query {int l,r,m,id;} qs[SZ]; bool operator < (query a,query b) { if(a.l/bs!=b.l/bs) return a.l/bs<b.l/bs; else return a.r<b.r; } #define Addq(l_,r_,m_,id_) ++qn, qs[qn].l=l_, qs[qn].r=r_, qs[qn].m=m_, qs[qn].id=id_; int cov[SZ],coa[SZ]; int ans=0,anss[SZ]; void edt(int p,int k) { ans-=(bool)coa[a[p]]; coa[a[p]]-=cov[p]&1; cov[p]+=k; coa[a[p]]+=cov[p]&1; ans+=(bool)coa[a[p]]; } int main() { scanf("%d%d",&n,&m); bs=sqrt(n)+1; for(int i=1;i<=n;i++) scanf("%d",a+i), as[i]=a[i]; sort(as+1,as+1+n); int nn=unique(as+1,as+1+n)-as-1; for(int i=1;i<=n;i++) a[i]=lower_bound(as+1,as+1+nn,a[i])-as; for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); adde(a,b); } dfs(1); dfs_(1); build(); for(int i=1;i<=m;i++) { int a,b,p; scanf("%d%d",&a,&b); p=lca(a,b); if(st[a]>st[b]) swap(a,b); if(p==a) Addq(st[a],st[b],0,i) else Addq(ed[a],st[b],p,i) } sort(qs+1,qs+1+qn); int l=1,r=0; for(int i=1;i<=qn;i++) { int ql=qs[i].l,qr=qs[i].r; while(l<ql) edt(dfx[l++],-1); while(l>ql) edt(dfx[--l],1); while(r>qr) edt(dfx[r--],-1); while(r<qr) edt(dfx[++r],1); if(qs[i].m) edt(qs[i].m,1); anss[qs[i].id]=ans; if(qs[i].m) edt(qs[i].m,-1); } for(int i=1;i<=m;i++) printf("%d\n",anss[i]); }