3653: 谈笑风生
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 866 Solved: 346
[ 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。
Output
输出 q 行,每行对应一个询问,代表询问的答案。
Sample Input
1 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
3
1
3
HINT
1<=P<=N
1<=K<=N
N<=300000
Q<=300000
Source
名字就很暴力
还是好搞的吧
首先询问的答案肯定是祖先中满足的对数+后代中满足的对数
祖先肯定简单了,我们来讨论一下后代
对于一个询问(p,k)
后代的对数肯定是Σsiz[j] (j为p的后代,且j与p的树上距离不超过k)
那这要怎么搞呢?
我们考虑把树转换成dfs序列
那么这时候答案为1 ~ dfn[p] + siz[p] - 1中距离不超过k的点的siz和 减去1 ~ dfn[p]中距离不超过k的点的siz和
用主席树算就好
代码:
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxseg = 6000000;
const int maxn = 300100;
vector<int> e[maxn];
int n,m,tme,rt[maxn];
LL lc[maxseg],rc[maxseg],sum[maxseg],tot;
int siz[maxn],dfn[maxn],fa[maxn],pos[maxn];
LL v[maxn],dep[maxn];
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline void dfs(int u,int fa)
{
siz[u]++;
pos[dfn[u] = ++tme] = dep[u];
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if (v == fa) continue;
dep[v] = dep[u] + 1;
dfs(v,u);
siz[u] += siz[v];
}
v[dfn[u]] = siz[u];
}
inline void maintain(int o)
{
sum[o] = sum[lc[o]] + sum[rc[o]];
}
inline int insert(int ac,int l,int r,int pos,LL x)
{
int o = ++tot;
sum[o] = sum[ac]; lc[o] = lc[ac]; rc[o] = rc[ac];
if (l == r)
{
sum[o] += x;
return o;
}
int mid = l + r >> 1;
if (pos <= mid) lc[o] = insert(lc[ac],l,mid,pos,x);
if (mid < pos) rc[o] = insert(rc[ac],mid + 1,r,pos,x);
maintain(o);
return o;
}
inline LL query(int o,int l,int r,int al,int ar)
{
if (al <= l && r <= ar) return sum[o];
int mid = l + r >> 1;
if (ar <= mid) return query(lc[o],l,mid,al,ar);
if (mid < al) return query(rc[o],mid + 1,r,al,ar);
if (al <= mid && mid < ar) return query(lc[o],l,mid,al,mid) + query(rc[o],mid + 1,r,mid + 1,ar);
}
int main()
{
n = getint(); m = getint();
for (int i = 1; i <= n - 1; i++)
{
int u = getint(),v = getint();
e[u].push_back(v);
e[v].push_back(u);
}
dep[1] = 1;
dfs(1,0);
for (int i = 1; i <= n; i++) rt[i] = insert(rt[i - 1],1,n,pos[i],v[i] - 1);
for (int i = 1; i <= m; i++)
{
int u = getint() , k = getint();
LL x1 = 0,x2 = 0;
if (siz[u] > 1)
{
x1 = query(rt[dfn[u] + siz[u] - 1],1,n,dep[u],dep[u] + k);
x2 = query(rt[dfn[u]],1,n,dep[u],dep[u] + k);
}
LL x3 = min(dep[u] - 1,k * 1ll) * (siz[u] - 1);
printf("%lld\n",x1 - x2 + x3);
}
return 0;
}