P3899 [湖南集训]谈笑风生

P3899 [湖南集训]谈笑风生

题目大意

n个节点的树,q次查询,每次查询给出a,k求三元组的数量(a,b,c),(a,b,c)的定义为:a、b均为c的祖先且距离<=k

离线,启发式合并线段树,长链剖分当然都能过这题

这里讲讲主席树的做法

dfs序建树

a为b的祖先时 查询a子树内深度<=dep[a]+k的节点的子树和

b为a祖先时 乘法原理就好

My complete code:

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=3e5+5;
const LL inf=1e18;
inline LL read(){
    LL x=0,f=1; char c=getchar();
    while(c<‘0‘||c>‘9‘){
        if(c==‘-‘) f=-1; c=getchar();
    }
    while(c>=‘0‘&&c<=‘9‘){
        x=x*10+c-‘0‘; c=getchar();
    }
    return x*f;
}
struct node{
    LL to,next;
}dis[maxn<<1];
LL num,cnt,n,q,nod;
LL head[maxn],dfn[maxn],low[maxn],root[maxn],a[maxn],b[maxn],dep[maxn],size[maxn];
LL rt[maxn<<7],lt[maxn<<7],sum[maxn<<7],date[maxn<<7];
inline void add(LL u,LL v){
    dis[++num]=(node){v,head[u]}; head[u]=num;
}
void dfs(LL u,LL fa){
    dfn[u]=++num;
    a[num]=u;
    b[num]=dep[u];
    size[u]=1;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa)
            continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
        size[u]+=size[v];
    }
    low[u]=num;
}
void update(LL &now,LL pre,LL l,LL r,LL c,LL u){
    now=++nod;
    date[now]=date[pre]+1;
    LL mid=(l+r)>>1;
    if(l==r){
        sum[now]=sum[pre]+size[u];
        return;
    }
    if(c<=mid){
        rt[now]=rt[pre];
        update(lt[now],lt[pre],l,mid,c,u);
    }else{
        lt[now]=lt[pre];
        update(rt[now],rt[pre],mid+1,r,c,u);
    }
    sum[now]=sum[lt[now]]+sum[rt[now]];
}
LL query(LL pre,LL next,LL l,LL r,LL c){
    LL mid=(l+r)>>1;
    if(l==r)
        return sum[next]-sum[pre];
    if(c-1<=mid)
        return query(lt[pre],lt[next],l,mid,c);
    else
        return query(rt[pre],rt[next],mid+1,r,c)+(sum[lt[next]]-sum[lt[pre]]);
}
int main(){
    n=read(); q=read();
    for(LL i=1;i<n;++i){
        LL u=read(),v=read();
        add(u,v); add(v,u);
    }
    num=0;
    dfs(1,0);
    cnt=n;
    b[++cnt]=inf;
    sort(b+1,b+1+cnt);
    cnt=unique(b+1,b+1+cnt)-b-1;
    for(LL i=1;i<=n;++i)
        --size[i];
    for(LL i=1;i<=n;++i){
        LL u=a[i];
        LL k=lower_bound(b+1,b+1+cnt,dep[u])-b;
        update(root[i],root[i-1],1,cnt,k,u);
    }
    while(q--){
        LL p=read(),k=read();
        LL l=dfn[p],r=low[p];
        LL now=upper_bound(b+1,b+1+cnt,dep[p]+k)-b;
        printf("%lld\n",query(root[l],root[r],1,cnt,now)+(size[p])*min(dep[p],k));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/y2823774827y/p/10090556.html

时间: 2024-10-16 16:37:06

P3899 [湖南集训]谈笑风生的相关文章

P3899 [湖南集训]谈笑风生 (线段树合并)

题目描述 设 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) 满足: a. b

题解 P3899 【[湖南集训]谈笑风生】

Luogu智能推荐给我搞的这个题啊,亦可赛艇! 题目链接 Solution [湖南集训]谈笑风生 题目大意:和Wallace谈笑风生,给定一棵有根树,多次询问给定点\(p\)和限制\(k\),求有多少对有序三元组\((p,b,c)\)满足\(p,b\)均为\(c\)的祖先且\(p,b\)间距离不超过\(k\) 主席树,树上差分 分析: 首先我们分类讨论一下 如果点\(b\)在点\(p\)上方时,有\(min(dep[p] - 1,k)\times(siz[p]-1)\),\(dep\)表示深度,

[湖南集训] 谈笑风生 (主席树)

[湖南集训] 谈笑风生 题目描述 设 T 为一棵有根树,我们做如下的定义: ? 设 a 和 b 为 T 中的两个不同节点.如果 a 是 b 的祖先,那么称"a 比 b 不知道高明到哪里去了". ? 设 a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称"a 与 b 谈笑风生". 给定一棵 n 个节点的有根树 T,节点的编号为 1 - n,根节点为 1 号节点.你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多

【[湖南集训]谈笑风生】

主席树板子了 首先看到这个暴力异常的题面,感觉做了这道题的会没命的 首先先考虑\(b\)在\(a\)子树内部的情况,这个样子的话我们需要知道子树内部所有深度小于等于\(deep[a]+k\)的点带来的贡献是是多少,由于这里的\(a,b,c\)都不能是同一个节点,所以这里的贡献就是子树大小减1,同时\(b\)也不能是\(a\) 之后按照深度建主席树就好了,权值是子树大小减1,我们就可以快速的查询点子树内部所有距离它的点小于等于\(k\)的点带来的权值和了 之后在考虑子树外部的情况,由于\(a,b\

湖南集训day1

早上八点20开始考试...题目自己做的并不好: 满分三百分 拿到了40: t1暴力的话是个简单的dfs,能拿到40分: t2暴力的话可以拿到10分: t3暴力的话可以拿到30分: 但是我t1文件输入写错了: 所以只拿到了40分: 题目难度仅仅是略高于noip,感觉自己还是菜: 考完后尧神是t2 60分是个shabi网络流......shabi般的lsj来这种板子都没看出来: 再想一下的话,其实今天可以拿的分应该有40+70+30=140的: 140也不低了: 所以还是要好好打好基础吧: 下午评卷

2015湖南集训DAY8——梦工厂

梦工厂 (yume.cpp/c/pas) Time Limit: 1 s Memory Limit: 128 M 问题描述 「有时候用烂了的名字也会别有深意」 --摘自EN 语录 "这里是制造快乐,编织幸福的梦工厂!才不是你们想的什么奇怪的工厂呢!哼!" 这是你来到这个奇妙的地方所听到的第一句话,竟然还是一头身长三米的狗熊发出来的. 一开始看到梦工厂这块牌匾时,你心里想的是什么呢?如果真的是洋溢着青涩而纯洁的 梦想,那就太棒了! 初来乍到,狗熊先生决定给你先大致地讲解一下工厂的运作过程

Noip前的大抱佛脚----数据结构

数据结构 线段树 注意:空间开4倍 神奇标记 From8.26 Test_zsy(CPU监控) 如果一个点权为\(val\)的点被打上了\((a,b)\)标记,那么他的实际点权为\(max(a+val,b)\) 干啥滴? 标记不下放 区间加标记不下放,维护区间max或者最大值 方法是当前\(tag\)维护当前区域标记,\(t\)维护左右儿子的\(max+tag[now]\),并没有快多少,如果仍然忘记见提交记录 并查集 维护二分图 并查集每个点维护是否要改颜色,然后按秩合并/按大小合并即可 实际

湖南省队集训 -- 1

不知道为什么今天状态 大 好 可能是暴力分比较简单吧,来认真写一下总结 开局睡了1h-- 然后考虑a题,发现特殊性:因为最后的和一定是10^n的,最后两个数一定是后面一段全是0,前面一段两个数的和是⑨,0和⑨中间夹一对和为10 然后脑补正解不能,暴力枚举一下好像可以,就是判断是在不好写 然后考虑b题,看N^2算法,脑玩了一下发现距离是不会变得,如果钦定了一个点建站第1~n-1个点产生的权值是不会变得,最后一个点的距离也变不了,唯一得变量需求要乘距离,然后把剩下的不变量加起来,这就是个kx+b的形

[BZOJ3653]谈笑风生

试题描述 设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