BZOJ3626: [LNOI2014]LCA

【传送门:BZOJ3626


简要题意:

  给出一棵树,设dep[i]为每个点与根节点的距离+1,

  有m个询问,每个询问输入l,r,z

  求出$\sum_{l<=i<=r}dep[LCA(i,z)]$


题解:

  读题,实际上dep[i]就表示i到根有多少个节点

  那么如果要求dep[LCA(i,j)]的话,就将i到根节点上的所有点权都+1,然后求j到根节点的路径的点权和就可以了(自行yy)

  然后肯定不能在线做,因为太大了

  那就离线吧

  开开心心打莫队,T了。。。O(mn0.5)都超时

  好吧,想另一种离线,看看,怎么和前缀和什么的有点关系

  直接将询问分成两个,一个是询问1到l-1,另一个是询问1到r

  然后分别记录在这两段区间里z向根节点的路径的点权和,然后把第二个区间得到的值-第一个区间得到的值就行了

  很显然是成立的

  然后就没了。


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct node
{
    int x,y,next;
}a[51000];int len,last[51000];
int Mod=201314;
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
struct trnode
{
    int l,r,lc,rc;
    LL c,lazy;
}tr[110000];int trlen;
void bt(int l,int r)
{
    trlen++;int now=trlen;
    tr[now].l=l;tr[now].r=r;tr[now].c=tr[now].lazy=0;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
int tot[51000],dep[51000],fa[51000],son[51000];
void pre_tree_node(int x)
{
    tot[x]=1;son[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            dep[y]=dep[x]+1;
            fa[y]=x;
            pre_tree_node(y);
            tot[x]+=tot[y];
            if(tot[y]>tot[son[x]]) son[x]=y;
        }
    }
}
int ys[51000],z,top[51000];
void pre_tree_edge(int x,int tp)
{
    ys[x]=++z;top[x]=tp;
    if(son[x]!=0) pre_tree_edge(son[x],tp);
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x]&&y!=son[x]) pre_tree_edge(y,y);
    }
}
void update(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc!=-1)
    {
        tr[lc].c=(tr[lc].c+(tr[lc].r-tr[lc].l+1)*tr[now].lazy)%Mod;
        tr[lc].lazy=(tr[lc].lazy+tr[now].lazy)%Mod;
    }
    if(rc!=-1)
    {
        tr[rc].c=(tr[rc].c+(tr[rc].r-tr[rc].l+1)*tr[now].lazy)%Mod;
        tr[rc].lazy=(tr[rc].lazy+tr[now].lazy)%Mod;
    }
    tr[now].lazy=0;
}
void change(int now,int l,int r,int c)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].c=(tr[now].c+c*LL(tr[now].r-tr[now].l+1))%Mod;
        tr[now].lazy=(tr[now].lazy+c)%Mod;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy!=0) update(now);
    if(r<=mid) change(lc,l,r,c);
    else if(l>mid) change(rc,l,r,c);
    else change(lc,l,mid,c),change(rc,mid+1,r,c);
    tr[now].c=(tr[lc].c+tr[rc].c)%Mod;
}
void modify(int x,int c)
{
    int tx=top[x];
    while(x!=0)
    {
        change(1,ys[tx],ys[x],c);
        x=fa[tx];tx=top[x];
    }
}
LL getsum(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r) return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazy!=0) update(now);
    if(r<=mid) return getsum(lc,l,r)%Mod;
    else if(l>mid) return getsum(rc,l,r)%Mod;
    else return (getsum(lc,l,mid)+getsum(rc,mid+1,r))%Mod;
}
LL solve(int x)
{
    int tx=top[x];LL ans=0;
    while(x!=0)
    {
        ans=(ans+getsum(1,ys[tx],ys[x]))%Mod;
        x=fa[tx];tx=top[x];
    }
    return ans;
}
struct cc
{
    int l,r,z,id;LL d;
}c[51000],q[110000];
bool cmp1(cc n1,cc n2)
{
    return n1.r<n2.r;
}
bool cmp2(cc n1,cc n2)
{
    return n1.id<n2.id;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    len=0;memset(last,0,sizeof(last));
    for(int i=2;i<=n;i++)
    {
        int f;
        scanf("%d",&f);f++;
        ins(f,i);
    }
    dep[1]=0;fa[1]=0;pre_tree_node(1);
    z=0;pre_tree_edge(1,1);
    trlen=0;bt(1,z);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].z);c[i].l++;c[i].r++;c[i].z++;
        q[2*i-1].r=c[i].l-1;q[2*i-1].z=c[i].z;q[2*i-1].id=2*i-1;
        q[2*i].r=c[i].r;q[2*i].z=c[i].z;q[2*i].id=2*i;
    }
    sort(q+1,q+2*m+1,cmp1);
    int r=0;
    for(int i=1;i<=2*m;i++)
    {
        while(r<q[i].r)
        {
            r++;
            modify(r,1);
        }
        q[i].d=solve(q[i].z);
    }
    sort(q+1,q+2*m+1,cmp2);
    for(int i=1;i<=m;i++) printf("%lld\n",(q[2*i].d-q[2*i-1].d+Mod)%Mod);
    return 0;
}

 

posted @ 2018-04-04 16:16  Star_Feel  阅读(134)  评论(0编辑  收藏  举报