• [BZOJ]3653: 谈笑风生


    题解:

    答案贡献分为两部分 

    第一部分为  b是a的祖先是  $ ans=min(dep[p]-1,k)*(num[p]-1) $

    第二部分为  b是a的子孙节点  对于dfs建深度主席树  每个点的权值为子孙节点个数 然后查询对应dfs序区间 及相应的深度范围

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int n,m;
    int dep[MAXN],num[MAXN],fa[MAXN],p[MAXN],fp[MAXN],cnt;
    void dfs(int x,int pre,int deep){
        dep[x]=deep+1;num[x]=1;fa[x]=pre;p[x]=++cnt;fp[p[x]]=x;
        link(x)if(j->t!=pre)dfs(j->t,x,deep+1),num[x]+=num[j->t];
    }
    
    typedef struct node{
        int l,r;ll sum;
    }node;
    node d[MAXN*21];
    int cnt1,rt[MAXN];
    
    void update(int &x,int y,int l,int r,int t,int k){
        x=++cnt1;d[x]=d[y];d[x].sum+=k;
        if(l==r)return ;
        int mid=(l+r)>>1;
        if(t<=mid)update(d[x].l,d[y].l,l,mid,t,k);
        else update(d[x].r,d[y].r,mid+1,r,t,k);
    }
    
    ll ans1;
    void query(int x,int y,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){ans1+=(d[y].sum-d[x].sum);return ;}
        int mid=(l+r)>>1;
        if(ql<=mid)query(d[x].l,d[y].l,l,mid,ql,qr);
        if(qr>mid)query(d[x].r,d[y].r,mid+1,r,ql,qr);
    }
    
    int main(){
        n=read();m=read();
        int u,v;
        inc(i,2,n)u=read(),v=read(),add(u,v),add(v,u);
        dfs(1,0,0);
        inc(i,1,cnt)update(rt[i],rt[i-1],1,n,dep[fp[i]],num[fp[i]]-1);
        while(m--){
    	u=read();v=read();
    	ll ans=1ll*min(dep[u]-1,v)*(num[u]-1);
    	ans1=0;query(rt[p[u]],rt[p[u]+num[u]-1],1,n,dep[u]+1,min(dep[u]+v,n));
    	printf("%lld
    ",ans1+ans);
        }
        return 0;
    }
    

      

    3653: 谈笑风生

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1278  Solved: 549
    [Submit][Status][Discuss]

    Description

    设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。

    Input

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

    Output

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

    Sample Input

    5 3
    1 2
    1 3
    2 4
    4 5
    2 2
    4 1
    2 3

    Sample Output

    3
    1
    3

    HINT

    Hint:边要加双向

        

  • 相关阅读:
    编程题目----约德尔测试
    编程题目----路灯
    java----java垃圾回收算法
    JAVA多线程和并发基础面试问答(转载)
    科学史上非常伟大的十位单身科学家
    MySQL----mysql57服务突然不见了的,解决方法
    linux:644、755、777权限详解
    Java 关键字 速查表
    java----鲁棒性
    习题----第六章 图(转)
  • 原文地址:https://www.cnblogs.com/wang9897/p/10363769.html
Copyright © 2020-2023  润新知