题目背景
2016.05.19 T2
题目描述
设 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 行,每行对应一个询问,代表询问的答案。
样例数据:
输入
5 3
1 2
1 3
2 4
4 5
2 2
4 1
2 3
输出
3
1
3
备注
【样例解释】
样例中的树如下图所示:
对于第一个和第三个询问,合法的三元组有 (2,1,4)、(2,1,5) 和 (2,4,5)。
对于第二个询问,合法的三元组只有 (4,2,5) 。
【数据规模与约定】
所有测试点的数据规模如下:
对于全部测试数据的所有询问,1≤p≤n,1≤k≤n。
分析: 吐槽一句,这次的题目让我感到好沧桑,无论生理上(-1s)还是心理上(orz做不起),暂时看着吧……(假装看懂了的样子)
代码:
30%(本人考场作,暴力dfs)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;ch>='0'&&ch<='9';ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
int n,q,p,k,tot;
long long ans;
int first[300010],nxt[600010],to[600010];
int dep[300010],son[300010];
int dfs(int root,int deep,int p)//找每个节点的所有儿子计数
{
dep[root]=deep;
for(p=first[root];p;p=nxt[p])
if(dep[to[p]]==-1)
{
son[root]=son[root]+1+dfs(to[p],deep+1,root);
}
return son[root];
}
void dfs3(int x,int num)//不要问我为什么是dfs3,因为dfs2最后被删掉了
{
for(int p=first[x];p;p=nxt[p])
{
int v=to[p];
if(dep[v]>dep[x]&&num<=k)
{
ans+=son[v];
if(num<k)
dfs3(v,num+1);
}
}
}
void add(int x,int y)
{
tot++;
nxt[tot]=first[x];
first[x]=tot;
to[tot]=y;
}
int main()
{
freopen("laugh.in","r",stdin);
freopen("laugh.out","w",stdout);
memset(dep,-1,sizeof(dep));
n=getint();q=getint();
for(int i=1;i<n;++i)
{
int x=getint();int y=getint();
add(x,y);
add(y,x);
}
dfs(1,0,0);
while(q--)
{
p=getint();k=getint();
ans+=min(dep[p],k)*son[p];//先是与它距离小于k的祖先肯定全部与它“谈笑风生”,而它的每个儿子都满足“矮到不知道哪里去了”
dfs3(p,1);//找它与它距离小于k的儿子,它能和所有这种儿子“谈笑风生”,而这种儿子的儿子都满足“矮到不知道哪里去了”
cout<<ans<<endl;
ans=0;
}
return 0;
}
100%
//无orz
本题结?No!No!No!没弄懂怎么能叫结呢?