【BZOJ3626】[LNOI2014]LCA 離線+樹鏈剖分+線段樹
阿新 • • 發佈:2017-11-05
log 根路徑 iostream 根節點 2個 scrip har eof family
0
0
1
1
1 4 3
1 4 2
5
【BZOJ3626】[LNOI2014]LCA
Description
給出一個n個節點的有根樹(編號為0到n-1,根節點為0)。一個點的深度定義為這個節點到根的距離+1。
設dep[i]表示點i的深度,LCA(i,j)表示i與j的最近公共祖先。
有q次詢問,每次詢問給出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]區間內的每個節點i與z的最近公共祖先的深度之和)
Input
第一行2個整數n q。
接下來n-1行,分別表示點1到點n-1的父節點編號。
接下來q行,每行3個整數l r z。
Output
輸出q行,每行表示一個詢問的答案。每個答案對201314取模輸出
Sample Input
5 20
0
1
1
1 4 3
1 4 2
Sample Output
85
HINT
共5組數據,n與q的規模分別為10000,20000,30000,40000,50000。
題解:考慮dep[lca(a,b)]可以表示成什麽,我們將a到根路徑上的每個節點的權值都+1,然後查詢b到根的路徑上的所有點的權值和即可。
發現這個東西是可以用前綴和來搞的。我們將詢問拆成前綴相減的形式,從1到n枚舉i,將i到根路徑上所有點的權值和+1,順便處理當前的所有詢問即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define mod 201314 #define lson x<<1 #define rson x<<1|1 using namespace std; const int maxn=50010; int n,m,sum,tot,cnt; int to[maxn],next[maxn],head[maxn],deep[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn],p[maxn]; int s[maxn<<2],t[maxn<<2],ans[maxn]; struct QUERY { int qx,org,k,qz; }q[maxn<<1]; inline int rd() { int ret=0; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) gc=getchar(); while(gc>=‘0‘&&gc<=‘9‘) ret=(ret<<3)+(ret<<1)+gc-‘0‘,gc=getchar(); return ret; } bool cmp(QUERY a,QUERY b) { return a.qx<b.qx; } void dfs1(int x) { siz[x]=1; for(int i=head[x];i!=-1;i=next[i]) { deep[to[i]]=deep[x]+1; dfs1(to[i]); siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[son[x]]) son[x]=to[i]; } } void dfs2(int x,int tp) { top[x]=tp,p[x]=++tot; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=son[x]) dfs2(to[i],to[i]); } void pushdown(int l,int r,int x) { if(t[x]) { int mid=(l+r)>>1; s[lson]=(s[lson]+(mid-l+1)*t[x])%mod; s[rson]=(s[rson]+(r-mid)*t[x])%mod; t[lson]+=t[x],t[rson]+=t[x],t[x]=0; } } void updata(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) { s[x]+=r-l+1,t[x]++; return ; } pushdown(l,r,x); int mid=(l+r)>>1; if(a<=mid) updata(l,mid,lson,a,b); if(b>mid) updata(mid+1,r,rson,a,b); s[x]=(s[lson]+s[rson])%mod; } int query(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) return s[x]; pushdown(l,r,x); int mid=(l+r)>>1; if(b<=mid) return query(l,mid,lson,a,b); if(a>mid) return query(mid+1,r,rson,a,b); return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b); } void insert(int x) { while(x) updata(1,n,1,p[top[x]],p[x]),x=fa[top[x]]; } int getsum(int x) { int ret=0; while(x) ret=(ret+query(1,n,1,p[top[x]],p[x]))%mod,x=fa[top[x]]; return ret; } void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } int main() { n=rd(),m=rd(); int i,j; memset(head,-1,sizeof(head)); for(i=2;i<=n;i++) fa[i]=rd()+1,add(fa[i],i); deep[1]=1; dfs1(1),dfs2(1,1); for(i=1;i<=m;i++) { q[i*2-1].qx=rd(),q[i*2].qx=rd()+1; q[i*2-1].qz=q[i*2].qz=rd()+1; q[i*2-1].k=-1,q[i*2].k=1; q[i*2-1].org=q[i*2].org=i; } sort(q+1,q+2*m+1,cmp); for(i=1;i<=2*m;i++) { for(j=q[i-1].qx+1;j<=q[i].qx;j++) insert(j); ans[q[i].org]+=q[i].k*getsum(q[i].qz); } for(i=1;i<=m;i++) printf("%d\n",(ans[i]+mod)%mod); return 0; }
【BZOJ3626】[LNOI2014]LCA 離線+樹鏈剖分+線段樹