[BZOJ3757]蘋果樹(樹上莫隊)

樹上莫隊共有三種寫法:spa

  1.按DFS序列分塊,和普通莫隊相似。常數大,不會被卡。指針

  2.按塊狀樹的方式分塊。常數小,會被菊花圖卡到O(n)。code

  3.按[BZOJ1086]王室聯邦的方式分塊。常數小,不會被卡。惟一的缺點是較抽象,一個塊多是不連通的。blog

權衡一下固然仍是寫第三種作法,具體看代碼。排序

而後還有一個問題,手動模擬莫隊移動左右端點指針的過程,會發現LCA處較難處理,它經常是跟其它點反着的。因而咱們每次移指針的時候都忽略LCA,最後詢問的時候加上LCA求解答案再減去LCA。再模擬會發現,全部方案均可以處理了。it

以及要注意每一個詢問若是左端點所在塊編號比右端點所在塊大則須要交換左右端點。詢問的排序方式是:若兩端點不在同一塊則按塊編號排序,不然按DFS序排序。也就是按(bel[i],dfn[i])的雙關鍵字排序。io

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 6 using namespace std;  7 
 8 const int N=200010;  9 int n,m,B,u,v,tim,top,tot,a[N],stk[N],b[N],dep[N],fa[N][20]; 10 int cnt,res,rt,vis[N],ans[N],dfn[N],s[N],h[N],to[N],nxt[N]; 11 struct P{ int l,r,x,y,id; }q[N]; 12 
13 bool cmp(const P &x,const P &y){ return b[x.l]==b[y.l] ? dfn[x.r]<dfn[y.r] : b[x.l]<b[y.l]; } 14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 15 
16 void dfs(int x){ 17     dfn[x]=++tim; int tmp=top; 18     rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1]; 19     For(i,x) if ((k=to[i])!=fa[x][0]){ 20         fa[k][0]=x; dep[k]=dep[x]+1; dfs(k); 21         if (top-tmp>=B){ ++tot; while (top!=tmp) b[stk[top--]]=tot; } 22  } 23     stk[++top]=x; 24 } 25 
26 int lca(int x,int y){ 27     if (dep[x]<dep[y]) swap(x,y); 28     int t=dep[x]-dep[y]; 29     for (int i=18; ~i; i--) if (t&(1<<i)) x=fa[x][i]; 30     if (x==y) return x; 31     for (int i=18; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; 32     return fa[x][0]; 33 } 34 
35 void upd(int x){ 36     if (vis[x]){ s[a[x]]--; if (!s[a[x]]) res--; } 37         else { s[a[x]]++; if (s[a[x]]==1) res++; } 38     vis[x]^=1; 39 } 40 
41 void work(int x,int y){ 42     for (; x!=y; upd(x),x=fa[x][0]) 43         if (dep[x]<dep[y]) swap(x,y); 44 } 45 
46 int main(){ 47     freopen("bzoj3757.in","r",stdin); 48     freopen("bzoj3757.out","w",stdout); 49     scanf("%d%d",&n,&m); B=sqrt(n); 50     rep(i,1,n) scanf("%d",&a[i]); 51     rep(i,1,n){ 52         scanf("%d%d",&u,&v); 53         if (!u || !v) { rt=u+v; continue; } 54  add(u,v); add(v,u); 55  } 56  dfs(rt); 57     while (top) b[stk[top--]]=tot; 58     rep(i,1,m){ 59         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].x,&q[i].y); q[i].id=i; 60         if (b[q[i].l]>b[q[i].r]) swap(q[i].l,q[i].r); 61  } 62     sort(q+1,q+m+1,cmp); 63     int L=rt,R=rt; 64     rep(i,1,m){ 65         work(L,q[i].l); work(R,q[i].r); L=q[i].l; R=q[i].r; 66         int f=lca(L,R); upd(f); 67         ans[q[i].id]=res-(int)(q[i].x!=q[i].y&&s[q[i].x]&&s[q[i].y]); upd(f); 68  } 69     rep(i,1,m) printf("%d\n",ans[i]); 70     return 0; 71 }
相關文章
相關標籤/搜索