zoukankan      html  css  js  c++  java
  • [Luogu P3899] [湖南集训]谈笑风生 (主席树)

    题面

    传送门:https://www.luogu.org/problemnew/show/P3899


    Solution

    你们搞的这道题啊,excited!

    这题真的很有意思。

    首先,我们可以先理解一下题面:固定一个a,找到一个b,c就是a与b的公共子树中的某个点

    那么,我们显然可以把这个b分成两类,第一种是在a上面的,第二种在a下面的

    对于b在a上面的情况,显然,c一定是a的子树中的某个点,答案即为min(K,depth[a])*size[a]

    对于b在a下面的情况,问题就会变得比较exciting了。

    我们可以考虑使用主席树来搞这个问题。

    考虑建一颗这样的主席树,以节点深度为主席树下标

    对于一个节点,如果B在这个节点上,那么,它对答案的贡献显然是它的size-1。

    那么,我们把它的贡献插入到它对应的主席树中(以深度为下标)。

    每一个子节点开一颗主席树,记录到它为止所有的深度的答案和,有点类似前缀和,以dfs序为时间轴

    这样,我们可以用一种类似树上差分的办法来“抠”出一颗子树对应的线段数(以深度为下标),这颗线段数中的[depth[x]+1,depth[x]+K]区间的sum就是这个x点的答案啦

    就酱,这题就被我们切掉啦٩(๑>◡<๑)۶ 


    Code

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    long long read()
    {
        long long x=0,f=1; char c=getchar();
        while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const long long N=300000+100;
    const long long M=N*30;
    struct SegmentTree
    {
        #define mid ((now_l+now_r)>>1)
        long long son[M][2],cnt;
        long long sum[M];
        inline void update(long long now)
        {
            sum[now]=sum[son[now][0]]+sum[son[now][1]];
        }
        void Build(long long now,long long now_l,long long now_r)
        {
            if(now_l==now_r) 
                return;    
            Build(son[now][0]=++cnt,now_l,mid);
            Build(son[now][1]=++cnt,mid+1,now_r);
        }
        void Add(long long x,long long num,long long now,long long pre,long long now_l,long long now_r)
        {
            if(now_l==now_r)
            {
                sum[now]=sum[pre];
                sum[now]+=num;
                return ;
            }
            if(x<=mid) son[now][1]=son[pre][1],Add(x,num,son[now][0]=++cnt,son[pre][0],now_l,mid);
            else son[now][0]=son[pre][0],Add(x,num,son[now][1]=++cnt,son[pre][1],mid+1,now_r);
            update(now);
        }
        long long Query(long long L,long long R,long long now,long long pre,long long now_l,long long now_r)
        {
            if(now_l>=L and now_r<=R)
                return sum[now]-sum[pre];
            long long ans=0;
            if(L<=mid) ans+=Query(L,R,son[now][0],son[pre][0],now_l,mid);
            if(R>mid) ans+=Query(L,R,son[now][1],son[pre][1],mid+1,now_r);
            return ans;
        }
        void Print(long long now,long long now_l,long long now_r)
        {
            cerr<<"no."<<now<<" now_l&r:"<<now_l<<" "<<now_r<<" sonl&r"<<son[now][0]<<" "<<son[now][1]<<" sum:"<<sum[now]<<endl;
            if(now_l!=now_r)
            {
                Print(son[now][0],now_l,mid);
                Print(son[now][1],mid+1,now_r);    
            }
        }    
        #undef mid
    }sgt;
    vector <long long> e[N];
    long long n,m,depth[N],size[N],dfn[N],dfn_to,r[N];
    void dfs2(long long now)
    {
        dfn[now]=++dfn_to;
        size[now]=1;
        for(long long i=0;i<(long long)(e[now].size());i++)
            if(depth[e[now][i]]==0)    
            {
                depth[e[now][i]]=depth[now]+1;
                dfs2(e[now][i]);
                size[now]+=size[e[now][i]];    
            }
    }
    void dfs(long long now)
    {
        r[dfn[now]]=++sgt.cnt;
        sgt.Add(depth[now],size[now]-1,r[dfn[now]],r[dfn[now]-1],1,n);
        //sgt.Print(r[dfn[now]],1,n);
        //cerr<<endl;
        for(long long i=0;i<(long long)(e[now].size());i++)
            if(depth[e[now][i]]>depth[now])
                dfs(e[now][i]);
    }
    int main()
    {
        n=read(),m=read();
        for(long long i=1;i<=n;i++)
            e[i].reserve(4);
        for(long long i=1;i<n;i++)
        {
            long long s=read(),t=read();
            e[s].push_back(t);
            e[t].push_back(s);    
        }
        
        sgt.Build(0,1,n);
        //sgt.Print(0,1,n);
        //cerr<<endl;
        depth[1]=1;
        dfs2(1);
        dfs(1);
        
        for(long long i=1;i<=m;i++)
        {
            long long p=read(),K=read();
            long long ans=sgt.Query(depth[p]+1,depth[p]+K,r[dfn[p]+size[p]-1],r[dfn[p]-1],1,n);
            ans+=min(K,depth[p]-1)*(size[p]-1);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    [Android-NDK编译] ndk 编译 c++ 兼容性问题汇总整理
    [云计算] 001.云计算简介
    eatwhatApp开发实战(十一)
    eatwhatApp开发实战(十)
    [Unity2d系列教程] 002.引用外部DLL
    Istio Sidecar
    Kubernetes Dashborad 搭建
    Istio 1.6架构及性能
    kubeadm 搭建kubernetes集群环境
    docker 安装
  • 原文地址:https://www.cnblogs.com/GoldenPotato/p/9801317.html
Copyright © 2011-2022 走看看