1. 程式人生 > >P4211[BZOJ 3626] [LNOI2014]LCA

P4211[BZOJ 3626] [LNOI2014]LCA

取模 build ans 數據 operator reg ron query lca

題目描述

給出一個n個節點的有根樹(編號為0到n-1,根節點為0)。一個點的深度定義為這個節點到根的距離+1。 設dep[i]表示點i的深度,LCA(i,j)表示i與j的最近公共祖先。 有q次詢問,每次詢問給出l r z,求 ∑l<=i<=r dep[LCA(i,z)]

輸入輸出格式

輸入格式:

第一行2個整數n q。 接下來n-1行,分別表示點1到點n-1的父節點編號。 接下來q行,每行3個整數l r z。

輸出格式:

輸出q行,每行表示一個詢問的答案。每個答案對201314取模輸出

輸入輸出樣例

輸入樣例#1: 復制
5 2
0
0
1
1
1 4 3
1 4 2
輸出樣例#1: 復制
8
5

說明

共5組數據,n與q的規模分別為10000,20000,30000,40000,50000。

題解

話說這題題解基本都是抄清華爺gconeice的吧……實在不會啊……

暴力的想法是,每次把要詢問的點向上打上標記,然後讓z點向上走,第一個遇到有標記的點就是lca

又因為lca的祖先也有標記,我們可以發現它的深度就是它祖先的標記總數

那麽我們可以把每個點到根的路徑都+1,然後詢問z到根的和,就是答案了

很明顯可以用樹剖或LCT解決(然而本蒟蒻寫不來LCT……)

多組詢問如何解決?

我們可以把區間[l,r]的答案拆成[1,r]-[1,l-1]

然後把詢問按端點排序,依次向後推,就可以滿足條件了……

ps:hzwer大佬強無敵……代碼看了我好久才弄明白怎麽回事orz

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 #define N 50005
  4 #define mod 201314
  5 using namespace std;
  6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
  7
char buf[1<<15],*p1=buf,*p2=buf; 8 typedef long long ll; 9 inline int read(){ 10 #define num ch-‘0‘ 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch==-)&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 int n,m,num,tot; 20 int sz[N],fa[N],son[N],cnt[N],rk[N],dep[N],top[N]; 21 int ver[N],Next[N],head[N]; 22 int sum[N<<2],tag[N<<2],l[N<<2],r[N<<2]; 23 struct que{int z,ans1,ans2;}q[N]; 24 struct data{int num,p;bool flag;}a[N<<1]; 25 bool operator <(data a,data b){return a.p<b.p;} 26 void add(int u,int v){ 27 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 28 } 29 void dfs1(int u){ 30 sz[u]=1;dep[u]=dep[fa[u]]+1; 31 for(int i=head[u];i;i=Next[i]){ 32 if(ver[i]==fa[u]) continue; 33 int v=ver[i]; 34 fa[v]=u; 35 dfs1(v); 36 sz[u]+=sz[v]; 37 if(!son[u]||sz[v]>sz[son[u]]) son[u]=v; 38 } 39 } 40 void dfs2(int u){ 41 if(top[u]==-1) top[u]=u; 42 cnt[u]=++num,rk[num]=u; 43 if(son[u]) top[son[u]]=top[u],dfs2(son[u]); 44 for(int i=head[u];i;i=Next[i]){ 45 int v=ver[i]; 46 if(v!=fa[u]&&v!=son[u]) dfs2(v); 47 } 48 } 49 void pushdown(int p){ 50 if(tag[p]){ 51 int lc=p<<1,rc=p<<1|1; 52 sum[lc]+=tag[p]*(r[lc]-l[lc]+1); 53 sum[rc]+=tag[p]*(r[rc]-l[rc]+1); 54 tag[lc]+=tag[p]; 55 tag[rc]+=tag[p]; 56 tag[p]=0; 57 } 58 } 59 void build(int p,int ll,int rr){ 60 l[p]=ll,r[p]=rr; 61 if(ll==rr) return; 62 int mid=(ll+rr)>>1; 63 build(p<<1,ll,mid); 64 build(p<<1|1,mid+1,rr); 65 } 66 void update(int p,int ll,int rr) 67 { 68 if(ll<=l[p]&&rr>=r[p]) 69 { 70 sum[p]+=r[p]-l[p]+1; 71 ++tag[p]; 72 return; 73 } 74 pushdown(p); 75 int mid=(l[p]+r[p])>>1; 76 if(ll<=mid) update(p<<1,ll,rr); 77 if(rr>mid) update((p<<1)+1,ll,rr); 78 sum[p]=sum[p<<1]+sum[p<<1|1]; 79 } 80 void solve_update(int x,int f){ 81 while(top[x]!=top[f]){ 82 update(1,cnt[top[x]],cnt[x]); 83 x=fa[top[x]]; 84 } 85 update(1,cnt[f],cnt[x]); 86 } 87 int query(int p,int ll,int rr) 88 { 89 if(ll<=l[p]&&rr>=r[p]) return sum[p]; 90 pushdown(p); 91 int mid=(l[p]+r[p])>>1; 92 int val=0; 93 if(ll<=mid) val+=query(p<<1,ll,rr); 94 if(rr>mid) val+=query((p<<1)+1,ll,rr); 95 return val; 96 } 97 int solve_query(int x,int f){ 98 int sum=0; 99 while(top[x]!=top[f]){ 100 sum+=query(1,cnt[top[x]],cnt[x]); 101 sum%=mod; 102 x=fa[top[x]]; 103 } 104 sum+=query(1,cnt[f],cnt[x]);sum%=mod; 105 return sum; 106 } 107 int main(){ 108 //freopen("testdata.in","r",stdin); 109 n=read(),m=read(); 110 memset(top,-1,sizeof(top)); 111 for(int i=1;i<n;++i){ 112 int x=read();add(x,i); 113 } 114 int tot=0; 115 for(int i=1;i<=m;++i){ 116 int l=read(),r=read(); 117 q[i].z=read(); 118 a[++tot].p=l-1,a[tot].num=i,a[tot].flag=0; 119 a[++tot].p=r,a[tot].num=i,a[tot].flag=1; 120 } 121 build(1,1,n); 122 sort(a+1,a+1+tot); 123 dfs1(0),dfs2(0); 124 int now=-1; 125 for(int i=1;i<=tot;++i){ 126 while(now<a[i].p){ 127 ++now; 128 solve_update(now,0); 129 } 130 int t=a[i].num; 131 if(!a[i].flag) q[t].ans1=solve_query(q[t].z,0); 132 else q[t].ans2=solve_query(q[t].z,0); 133 } 134 for(int i=1;i<=m;++i) 135 printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod); 136 return 0; 137 }

P4211[BZOJ 3626] [LNOI2014]LCA