BZOJ3626: [LNOI2014]LCA

来源:互联网 发布:java调用构造方法是在 编辑:程序博客网 时间:2024/05/21 09:54

题目大意:给一棵树,q个询问,每次询问一个区间内的点与一个点的所有LCA的深度之和


很神的一道题啊...

首先对于每组询问,我们可以把这个区间内每个点到根的路径都+1,然后求被询问的点到根的路径和,就是这个询问的答案

然后我们可以把每组询问拆成两个,变成ans[R]-ans[L-1]

然后就可以离线,把0~n-1一个一个往里加,每次把它到根的路径+1,然后查询对应的那些询问就可以了


#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> #define N 100010using namespace std;int to[N],nxt[N],pre[N],fa[N],cnt;void ae(int ff,int tt){cnt++;to[cnt]=tt;nxt[cnt]=pre[ff];pre[ff]=cnt;}int d[N],zs[N],siz[N];void build1(int x){int maxn=0,maxb=0;int i,j;siz[x]=1;for(i=pre[x];i;i=nxt[i]){j=to[i];d[j]=d[x]+1;fa[j]=x;build1(j);siz[x]+=siz[j];if(siz[j]>maxn){maxn=siz[j];maxb=j;}}zs[x]=maxb;}int top[N],sit[N],fan[N],cn;void make(int x,int tt){cn++;sit[x]=cn;fan[cn]=x;top[x]=tt;int i,j;if(zs[x]) make(zs[x],tt);for(i=pre[x];i;i=nxt[i]){j=to[i];if(j==zs[x]) continue;make(j,j);}}struct ppp{int x,z,num,v;}b[N];bool cmp(ppp x,ppp y){return x.x<y.x;}int ans[N];int l[N<<2],r[N<<2],sum[N<<2],t[N<<2];void pup(int x){sum[x]=sum[x<<1]+sum[x<<1|1];}void pud(int x){sum[x<<1]+=(r[x<<1]-l[x<<1]+1)*t[x];sum[x<<1|1]+=(r[x<<1|1]-l[x<<1|1]+1)*t[x];t[x<<1]+=t[x];t[x<<1|1]+=t[x];t[x]=0;}void build(int now,int ll,int rr){l[now]=ll;r[now]=rr;if(ll==rr) return;int mid=(ll+rr)>>1;build(now<<1,ll,mid);build(now<<1|1,mid+1,rr);}void change(int now,int ll,int rr){if(l[now]==ll&&r[now]==rr){t[now]++;sum[now]+=r[now]-l[now]+1;return;}if(t[now]) pud(now);int mid=(l[now]+r[now])>>1;if(rr<=mid) change(now<<1,ll,rr);else if(ll>mid) change(now<<1|1,ll,rr);else change(now<<1,ll,mid),change(now<<1|1,mid+1,rr);pup(now);}int check(int now,int ll,int rr){if(l[now]==ll&&r[now]==rr) return sum[now];if(t[now]) pud(now);int mid=(l[now]+r[now])>>1;if(rr<=mid) return check(now<<1,ll,rr);else if(ll>mid) return check(now<<1|1,ll,rr);else return check(now<<1,ll,mid)+check(now<<1|1,mid+1,rr);}void changeit(int x){while(x){change(1,sit[top[x]],sit[x]);x=fa[top[x]];}}int checkit(int x){int ans=0;while(x){ans+=check(1,sit[top[x]],sit[x]);x=fa[top[x]];}return ans;}int mod=201314;int main(){int n,q;scanf("%d%d",&n,&q);int i,j,x,y,z;for(i=2;i<=n;i++){scanf("%d",&x);ae(x+1,i);}build1(1);make(1,1);for(i=1;i<=q;i++){scanf("%d%d%d",&x,&y,&z);x++;y++;z++;b[2*i-1]=(ppp){x-1,z,i,-1};b[2*i]=(ppp){y,z,i,1};}sort(b+1,b+2*q+1,cmp);j=1;while(b[j].x==0) j++;build(1,1,n);for(i=1;i<=n;i++){changeit(i);while(b[j].x==i){ans[b[j].num]+=b[j].v*checkit(b[j].z);j++;}}for(i=1;i<=q;i++)printf("%d\n",ans[i]%mod);}

0 0