并不对劲的bzoj3626:loj2558:p4211:[LNOI2014]LCA

题目大意

有一棵有\(n\)(\(n\leq5*10^4\))个点的树,\(q\)(\(q\leq5*10^4\))次询问,每次给出\(l,r,x\)表示询问所有编号在\([l,r]\)的点与点\(x\)的LCA的深度之和

题解

\([l,r]\)里每个点和该点的所有祖先点权+1后,查询点\(x\)和它的祖先的点权和就行了
可持久化线段树维护

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define maxn 50010
#define ls (son[u][0])
#define rs (son[u][1])
#define lsa son[ua][0]
#define rsa son[ua][1]
#define lsb son[ub][0]
#define rsb son[ub][1]
#define mi (l+r>>1)
#define LL long long
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x==0){putchar('0'),putchar('\n');return;}
    int f=0;char ch[20];
    if(x<0)putchar('-'),x=-x;
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
    return;
}
const int mod=201314;
int n,q,rt[maxn],tr[maxn<<7],mk[maxn<<7],son[maxn<<7][2],ver[maxn<<7],fir[maxn],nxt[maxn],v[maxn],cnt,fa[maxn];
int dfn[maxn],tim,wson[maxn],siz[maxn],top[maxn],cntnd;
void ade(int u1,int v1){v[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
void getsiz(int u)
{
    siz[u]=1;
    view(u,k)if(v[k]!=fa[u])
    {
        getsiz(v[k]),siz[u]+=siz[v[k]];
        if(siz[v[k]]>siz[wson[u]])wson[u]=v[k];
    }
}
void gettop(int u,int anc)
{
    top[u]=anc,dfn[u]=++tim;
    if(wson[u])gettop(wson[u],anc);
    view(u,k)if(v[k]!=fa[u]&&v[k]!=wson[u])gettop(v[k],v[k]);
}
int mo(int x){if(x>=mod)return x-mod;if(x<0)return x+mod;return x;}
int build(int l,int r)
{
    int u=++cntnd;
    if(l==r){return u;}
    ls=build(l,mi),rs=build(mi+1,r);
    return u;
}
int add(int u,int l,int r,int x,int y,int vers)
{
    int nu=vers==ver[u]?u:++cntnd;
    if(x<=l&&r<=y){son[nu][0]=ls,son[nu][1]=rs,ver[nu]=vers,tr[nu]=mo(tr[u]+r-l+1),mk[nu]=mo(mk[u]+1);return nu;}
    ver[nu]=vers,tr[nu]=mo(tr[u]+y-x+1),mk[nu]=mk[u];
    if(x<=mi)son[nu][0]=add(ls,l,mi,x,min(mi,y),vers);
    else son[nu][0]=ls;
    if(y>mi)son[nu][1]=add(rs,mi+1,r,max(x,mi+1),y,vers);
    else son[nu][1]=rs;
    return nu;
}
int ask(int ua,int ub,int l,int r,int x,int y,int ad)
{
    if(x<=l&&r<=y){return mo(mo(tr[ua]-tr[ub])+(LL)ad*(LL)(y-x+1)%mod);}
    int lans=0,rans=0;
    if(x<=mi)lans=ask(lsa,lsb,l,mi,x,min(mi,y),mo(ad+mo(mk[ua]-mk[ub])));
    if(y>mi)rans=ask(rsa,rsb,mi+1,r,max(x,mi+1),y,mo(ad+mo(mk[ua]-mk[ub])));
    return mo(lans+rans);
}
int main()
{
    memset(fir,-1,sizeof(fir));
    n=read(),q=read();
    rep(i,2,n)fa[i]=read()+1,ade(fa[i],i);
    getsiz(1),gettop(1,1);rt[0]=build(1,n);
    rep(i,1,n)
    {
        rt[i]=rt[i-1];int x=i;
        while(top[x]!=1){rt[i]=add(rt[i],1,n,dfn[top[x]],dfn[x],i);x=fa[top[x]];}
        rt[i]=add(rt[i],1,n,1,dfn[x],i);
    }
    while(q--)
    {
        int l=read()+1,r=read()+1,x=read()+1,ans=0;
        while(top[x]!=1){ans=mo(ans+ask(rt[r],rt[l-1],1,n,dfn[top[x]],dfn[x],0));x=fa[top[x]];}
        ans=mo(ans+ask(rt[r],rt[l-1],1,n,1,dfn[x],0));
        write(ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xzyf/p/10423891.html