[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\n",ans1+ans);
}
return 0;
}
3653: 谈笑风生
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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
1 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
3
1
3
1
3
HINT
Hint:边要加双向

浙公网安备 33010602011771号