bzoj3626:[LNOI2014]LCA
題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626
Description
給出一個(gè)n個(gè)節(jié)點(diǎn)的有根樹(shù)(編號(hào)為0到n-1,根節(jié)點(diǎn)為0)。一個(gè)點(diǎn)的深度定義為這個(gè)節(jié)點(diǎn)到根的距離+1。
設(shè)dep[i]表示點(diǎn)i的深度,LCA(i,j)表示i與j的最近公共祖先。
有q次詢(xún)問(wèn),每次詢(xún)問(wèn)給出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]區(qū)間內(nèi)的每個(gè)節(jié)點(diǎn)i與z的最近公共祖先的深度之和)
Input
第一行2個(gè)整數(shù)n q。
接下來(lái)n-1行,分別表示點(diǎn)1到點(diǎn)n-1的父節(jié)點(diǎn)編號(hào)。
接下來(lái)q行,每行3個(gè)整數(shù)l r z。
Output
輸出q行,每行表示一個(gè)詢(xún)問(wèn)的答案。每個(gè)答案對(duì)201314取模輸出
Sample Input
5 20
0
1
1
1 4 3
1 4 2
Sample Output
85
HINT
共5組數(shù)據(jù),n與q的規(guī)模分別為10000,20000,30000,40000,50000。
題解:
樹(shù)鏈剖分,雖然題目是lca,然而好像并沒(méi)有什么關(guān)系。題目查詢(xún)的是在l到r區(qū)間中,與z的最近公共祖先的深度之和。然后很明顯可以知道兩點(diǎn)到根節(jié)點(diǎn)經(jīng)過(guò)的共同節(jié)點(diǎn)個(gè)數(shù)為其公共祖先的深度,比如樣例中4和5共同經(jīng)過(guò)1和2,而他們的最近公共祖先為2,其深度為2。然后求l到r之間的,可以轉(zhuǎn)換為[1,l]-[1,r-1]的差。那么就可以對(duì)于查詢(xún)離線,把詢(xún)問(wèn)分成兩部分,按值來(lái)排序,比如[1,4,3],就分成[0,3]和[4,3]。查詢(xún)時(shí)把需要加的點(diǎn)一個(gè)個(gè)加進(jìn)去,當(dāng)?shù)竭_(dá)一個(gè)點(diǎn)恰好為某個(gè)詢(xún)問(wèn)的值,那么就可以把這個(gè)詢(xún)問(wèn)的答案來(lái)更新一下了。值的定義為分成兩部分后區(qū)間的右端點(diǎn),左端點(diǎn)恒為1。
代碼:
#include<iostream> #include<cmath> #include<cstring> #include<cstdlib> #include<cstdio> #include<ctime> #include<queue> #include<vector> #include<algorithm> #define mo 201314 #define N 300010 using namespace std; long long sum,ans[N]; int tot,p,q,n,u,v; long long lazy[N],b[N]; int siz[N],fa[N],son[N],dep[N],head[N],top[N],w[N]; struct h1{int next,to;}tu[N]; struct data{int l,f,w,wei;}a[2*N]; int getint() {int res=0,w=1;char ch=getchar();while ((ch>'9' || ch<'0')&&ch!='-') ch=getchar();if (ch=='-') w=-1,ch=getchar();while (ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();return res*w; } void link(int x,int y) {tu[++sum].next=head[x]; head[x]=sum; tu[sum].to=y; } void dfs1(int p) {siz[p]=1;for (int i=head[p];i;i=tu[i].next){int v=tu[i].to;if (v==fa[p]) continue;dep[v]=dep[p]+1;dfs1(v); siz[p]+=siz[v]; if (siz[v]>siz[son[p]]) son[p]=v;} } void dfs2(int p,int t) {top[p]=t; w[p]=++tot;if (son[p]) dfs2(son[p],t);for (int i=head[p];i;i=tu[i].next)if (tu[i].to!=son[p]&&tu[i].to!=fa[p]) dfs2(tu[i].to,tu[i].to); } bool cmp(data a,data b) {return a.l<b.l;} void tree_add(int x,int l,int r,int L,int R) {if (l==L&&r==R) lazy[x]=(lazy[x]+1)%mo;else{b[x]=(b[x]+R-L+1)%mo;int mid=(l+r)>>1;if (L>mid) tree_add((x<<1)+1,mid+1,r,L,R);else if (R<=mid) tree_add(x<<1,l,mid,L,R);else tree_add(x<<1,l,mid,L,mid),tree_add((x<<1)+1,mid+1,r,mid+1,R);} } void tree_find(int x,int l,int r,int L,int R) {if (l==L&&r==R) sum=(sum+b[x]+1LL*lazy[x]*(r-l+1))%mo;else{int mid=(l+r)>>1;lazy[x<<1]=(lazy[x<<1]+lazy[x])%mo;lazy[(x<<1)+1]=(lazy[(x<<1)+1]+lazy[x])%mo;b[x]=(b[x]+1LL*lazy[x]*(r-l+1))%mo;lazy[x]=0;if (R<=mid) tree_find(x<<1,l,mid,L,R);else if (L>mid) tree_find((x<<1)+1,mid+1,r,L,R);else tree_find(x<<1,l,mid,L,mid),tree_find((x<<1)+1,mid+1,r,mid+1,R);} } void add(int p) {while (p!=0){tree_add(1,1,n,w[top[p]],w[p]);p=fa[top[p]];} } void find(int p) {while (p!=0){tree_find(1,1,n,w[top[p]],w[p]);p=fa[top[p]];} } int main() {n=getint(); q=getint();for (int i=2;i<=n;i++){p=getint()+1;fa[i]=p; link(p,i);}dep[1]=1; dfs1(1);dfs2(1,1); tot=0;for (int i=1;i<=q;i++){u=getint()+1; v=getint()+1; p=getint()+1;a[++tot].l=u-1; a[tot].f=-1; a[tot].wei=i; a[tot].w=p;a[++tot].l=v; a[tot].f=1; a[tot].wei=i; a[tot].w=p;}sort(a+1,a+1+tot,cmp);u=0; for (int i=1;i<=tot;i++){while (u<a[i].l) u++,add(u);sum=0; find(a[i].w);ans[a[i].wei]=(ans[a[i].wei]+1LL*sum*a[i].f+mo)%mo;}for (int i=1;i<=q;i++)printf("%lld\n",ans[i]);return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/xiaoqiang200015/p/6016006.html
總結(jié)
以上是生活随笔為你收集整理的bzoj3626:[LNOI2014]LCA的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: sublime 自定义快捷键
- 下一篇: BroadcastReceive之ip拨