• COGS 2211. [BZOJ3653]谈笑风生


    ★★★★   输入文件:laugh.in   输出文件:laugh.out   简单对比
    时间限制:3 s   内存限制:512 MB

    【问题描述】

        设T 为一棵有根树,我们做如下的定义:    

        • 设a和b为T 中的两个不同节点。如果a是b的祖先,那么称“a比b不知道高明到哪里去了”。    

        • 设a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定常数x,那么称“a 与b 谈笑风生”。

        给定一棵n个节点的有根树T,节点的编号为1  n,根节点为1号节点。你需要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a; b; c)满足: 

        1. a、b和 c为 T 中三个不同的点,且 a为p 号节点;    

        2. a和b 都比 c不知道高明到哪里去了;    

        3. a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。

    【输入格式】

        输入文件的第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。接下来n-1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。接下来q 行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。

    【输出格式】输出 q 行,每行对应一个询问,代表询问的答案。

    laugh.in 

    5 3

    1 2

    1 3

    2 4

    4 5

    2 2

    4 1

    2 3

    laugh.out

    3

    1

    3

        数据范围 n<=300,000吧

    主席树+dfs序

    从要求看来,可以划分成两种情况:

    1.b比a高明且a和b谈笑风生,那么c只需在a的子树中取就好了,此时贡献为size[p]*min(dep[p-1],k)

    2.a比b高明且a和b谈笑风生,c在b的子树上,考虑到子树问题,想到dfs序,那么问题变为求子树a区间中深度在deep[p]+1~deep[p]+k中所有点size的和 ,这可以用主席树完成

    屠龙宝刀点击就送

    #include <ctype.h>
    #include <vector>
    #include <cstdio>
    #define N 305000
    typedef long long LL;
     
    using std::vector;
    struct cmt
    {
        int l,r;
        LL Size;
    }tr[N*20];
    inline void Read(int &x)
    {
        register char ch=getchar();
        for(x=0;!isdigit(ch);ch=getchar());
        for(;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    }
    LL ans;
    int min(int a,int b) {return a>b?b:a;}
    int max(int a,int b) {return a>b?a:b;}
    vector<int>edge[N];
    int t[N],dfn[N],l[N],r[N],n,q,dep[N],tim,siz[N],tot;
    void dfs(int x,int fa)
    {
        l[x]=++tim;
        dfn[tim]=x;
        dep[x]=dep[fa]+1;
        siz[x]=0;
        for(int i=0;i<edge[x].size();++i)
        {
            int v=edge[x][i];
            if(v!=fa)
            {
                dfs(v,x);
                siz[x]+=siz[v]+1;
            }
        }
        r[x]=tim;
    }
    void update(int l,int r,int x,int &y,int a,int b)
    {
        y=++tot;
        tr[y].Size=tr[x].Size+b;
        if(l==r) return;
        tr[y].l=tr[x].l;
        tr[y].r=tr[x].r;
        int mid=(l+r)>>1;
        if(a<=mid) update(l,mid,tr[x].l,tr[y].l,a,b);
        else update(mid+1,r,tr[x].r,tr[y].r,a,b);
    }
    LL ask(int l,int r,int x,int y,int a,int b)
    {
        if(l==a&&r==b) return tr[y].Size-tr[x].Size;
        int mid=(l+r)>>1;
        if(a>mid) return ask(mid+1,r,tr[x].r,tr[y].r,a,b);
        else if(b<=mid) return ask(l,mid,tr[x].l,tr[y].l,a,b);
        else return ask(l,mid,tr[x].l,tr[y].l,a,mid)+ask(mid+1,r,tr[x].r,tr[y].r,mid+1,b);
    }
    int main(int argc,char *argv[])
    {
        freopen("laugh.in","r",stdin);
        freopen("laugh.out","w",stdout);
        Read(n);
        Read(q);
        for(int u,v,i=1;i<n;++i)
        {
            Read(u);
            Read(v);
            edge[u].push_back(v); 
            edge[v].push_back(u); 
        }
        dfs(1,1);
        for(int i=1;i<=n;++i) update(1,n,t[i-1],t[i],dep[dfn[i]],siz[dfn[i]]);
        for(int p,k;q--;)
        {
            Read(p);
            Read(k);
            ans=0;
            ans=(LL)siz[p]*min(dep[p]-1,k);
            if(dep[p]!=n) ans+=ask(1,n,t[l[p]-1],t[r[p]],dep[p]+1,min(n,dep[p]+k));
            printf("%lld
    ",ans);
        }
        return 0;
    }
    我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。
  • 相关阅读:
    oracle安装异常汇总
    使用口令文件认证
    oracle的网络连接
    只有数据文件恢复数据库
    ORACLE-SQLLOAD导入外部数据详解
    主,备数据库--静态监听配置
    使用RMAN Active duplicate创建异地auxiliary Database
    maven仓库之第一篇
    Oracle数据库之第四篇
    Oracle数据库之第三篇
  • 原文地址:https://www.cnblogs.com/ruojisun/p/7405808.html
Copyright © 2020-2023  润新知