• 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
    ",(q[2*i].d-q[2*i-1].d+Mod)%Mod);
        return 0;
    }

     

  • 相关阅读:
    Redis学习03:Redis数据持久化
    Redis学习02:Redis数据类型
    项目总结42:Linux下vim操作常用指令
    Java深入学习02:CAS 算法以及低层原理
    Java深入学习01:volatile的原理和使用
    项目总结39:Springboot打jar包并本地运行
    项目总结38:使用httpcomponents: httpclient请求数据
    项目总结37:Java上传图片保存到Oracle以及读取图片
    Redis学习01:Redis配置文件redis.conf详解
    Oracle学习笔记04:timestamp时间大小比较
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8717890.html
Copyright © 2020-2023  润新知