P4211[BZOJ 3626] [LNOI2014]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取模输出
输入输出样例
说明
共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 }
深深地明白自己的弱小