1. 程式人生 > >[LNOI2014]LCA

[LNOI2014]LCA

sam 規律 公共祖先 wap pda push iostream 表示 每次

[LNOI2014]LCA

題目

給出一個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 2
0
0
1
1
1 4 3
1 4 2

OUTPUT

8

5

解題報告

首先提出一個結論

$x$點與$y$點的$LCA$可以由如下方式求得:

將$x$點到根路徑上所有點點權置為$1$,其余點點權置為$0$,則$y$點到根路徑上點權和即為所求

原因很簡單,手畫一下就可以發現這個規律

有了這個結論,我們就可以把求$LCA$這種操作轉化為路徑上的點權操作了,也就是說,樹鏈剖分就可行了起來

我們考慮如何處理一段區間的貢獻,顯然可以用差分來搞,那麽我們就可以將操作離線,將詢問拆成兩個,進行差分,掃一遍節點,進行點權覆蓋與差分查詢即可

技術分享
 1
#include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <vector> 5 using namespace std; 6 inline int read(){ 7 int sum(0);char ch(getchar()); 8 for(;ch<0||ch>9;ch=getchar()); 9 for(;ch>=0&&ch<=9;sum=sum*10+(ch^48
),ch=getchar()); 10 return sum; 11 } 12 const int mod(201314); 13 struct edge{int e;edge *n;}*pre[50005]; 14 inline void insert(int s,int e){edge *tmp(new edge);tmp->e=e;tmp->n=pre[s];pre[s]=tmp;} 15 int n,q; 16 int z[50005]; 17 vector<int>sub[50005],add[50005]; 18 int sum[200005],lazy[200005]; 19 inline void pushup(int i){sum[i]=(sum[i<<1]+sum[i<<1|1])%mod;} 20 inline void pushdown(int i,int len){ 21 if(lazy[i]){ 22 lazy[i<<1]=(lazy[i<<1]+lazy[i])%mod; 23 lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i])%mod; 24 sum[i<<1]=(sum[i<<1]+lazy[i]*(len-(len>>1))%mod)%mod; 25 sum[i<<1|1]=(sum[i<<1|1]+lazy[i]*(len>>1)%mod)%mod; 26 lazy[i]=0; 27 } 28 } 29 inline void update(int ll,int rr,int w,int l,int r,int i){ 30 if(ll<=l&&r<=rr){lazy[i]=(lazy[i]+w)%mod;sum[i]=(sum[i]+w*(r-l+1)%mod)%mod;return;} 31 int mid((l+r)>>1);pushdown(i,r-l+1); 32 if(ll<=mid)update(ll,rr,w,l,mid,i<<1);if(mid<rr)update(ll,rr,w,mid+1,r,i<<1|1);pushup(i); 33 } 34 inline int query(int ll,int rr,int l,int r,int i){ 35 if(ll<=l&&r<=rr)return sum[i];int ret(0),mid((l+r)>>1);pushdown(i,r-l+1); 36 if(ll<=mid)ret=query(ll,rr,l,mid,i<<1);if(mid<rr)ret=(ret+query(ll,rr,mid+1,r,i<<1|1))%mod;return ret; 37 } 38 int ans[50005]; 39 int fa[50005],son[50005],size[50005],dep[50005]; 40 inline void dfs1(int u){ 41 son[u]=0;size[u]=1; 42 for(edge *i=pre[u];i;i=i->n){ 43 int e(i->e);dep[e]=dep[u]+1;dfs1(e); 44 size[u]+=size[e];if(size[e]>size[son[u]])son[u]=e; 45 } 46 } 47 int cnt,id[50005],pos[50005],top[50005]; 48 inline void dfs2(int u,int rt){ 49 top[u]=rt;id[u]=++cnt;pos[cnt]=u;if(son[u])dfs2(son[u],rt); 50 for(edge *i=pre[u];i;i=i->n){int e(i->e);if(e==son[u])continue;dfs2(e,e);} 51 } 52 inline void change(int x,int y){ 53 while(top[x]^top[y]){ 54 if(dep[top[x]]<dep[top[y]])swap(x,y); 55 update(id[top[x]],id[x],1,1,n,1); 56 x=fa[top[x]]; 57 } 58 if(dep[x]>dep[y])swap(x,y); 59 update(id[x],id[y],1,1,n,1); 60 } 61 inline int ask(int x,int y){ 62 int ret(0); 63 while(top[x]^top[y]){ 64 if(dep[top[x]]<dep[top[y]])swap(x,y); 65 ret=(ret+query(id[top[x]],id[x],1,n,1))%mod; 66 x=fa[top[x]]; 67 } 68 if(dep[x]>dep[y])swap(x,y); 69 ret=(ret+query(id[x],id[y],1,n,1))%mod; 70 return ret; 71 } 72 int main(){ 73 n=read();q=read(); 74 for(int i=2;i<=n;++i){ 75 int x(read()+1);fa[i]=x;insert(x,i); 76 } 77 for(int i=1;i<=q;++i){ 78 int x(read()+1),y(read()+1);z[i]=read()+1; 79 sub[x-1].push_back(i);add[y].push_back(i); 80 } 81 dfs1(1);dfs2(1,1); 82 for(int i=1;i<=n;++i){ 83 change(i,1); 84 for(int j=0,k=sub[i].size();j<k;++j) 85 ans[sub[i][j]]=((ans[sub[i][j]]-ask(z[sub[i][j]],1))%mod+mod)%mod; 86 for(int j=0,k=add[i].size();j<k;++j) 87 ans[add[i][j]]=(ans[add[i][j]]+ask(z[add[i][j]],1))%mod; 88 } 89 for(int i=1;i<=q;++i)printf("%d\n",ans[i]); 90 }
View Code

[LNOI2014]LCA