您的位置:首页 > 其它

3653: 谈笑风生

2016-05-20 17:20 281 查看

3653: 谈笑风生

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 498  Solved: 185

[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

5 3

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



[Submit][Status][Discuss]


维护dfs序的线段树

每次询问的b要么在a上面(每组的权值是size[a])要么在a下面(每组权值size[b])

然后距离都不超过k

第一种很好处理

第二种在线段树一段区间里面还需满足深度符合

也就是线段树需要两个关键字判断(dfs序与深度)

这样的询问每次是O(log^2)的



一开始也不知道为什么想bfs序?显然不可以

然后query函数里面没及时return 0



#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;

const int maxn = 4E5 + 30;
typedef long long LL;

int n,m,p,k,clo,dfi[maxn],dfo[maxn],siz[maxn],L[maxn];
LL c[maxn*20];
int ac[maxn*20],bc[maxn*20];

vector <int> v[maxn];

void build(int o,int l,int r,int pos,int Add,int de)
{
if (l == r) {c[o] = Add; ac[o] = bc[o] = de; return;}
int mid = (l+r) >> 1;
if (pos <= mid) build(2*o,l,mid,pos,Add,de);
else build(2*o+1,mid+1,r,pos,Add,de);
c[o] = c[2*o] + c[2*o+1];
ac[o] = min(ac[2*o],ac[2*o+1]);
bc[o] = max(bc[2*o],bc[2*o+1]);
}

void dfs(int k)
{
dfi[k] = ++clo;
for (int i = 0; i < v[k].size(); i++) {
int to = v[k][i];
if (L[to]) continue;
L[to] = L[k] + 1;
dfs(to);
siz[k] += siz[to] + 1;
}
dfo[k] = clo;
build(1,1,n,dfi[k],siz[k],L[k]);
}

LL query(int o,int l,int r,int ql,int qr,int qa,int qb)
{
if (ql <= l && r <= qr && qa <= ac[o] && bc[o] <= qb) return c[o];
if (bc[o] < qa || qb < ac[o]) return 0;
int mid = (l+r) >> 1; LL ret = 0;
if (ql <= mid) ret += query(2*o,l,mid,ql,qr,qa,qb);
if (qr > mid) ret += query(2*o+1,mid+1,r,ql,qr,qa,qb);
return ret;
}

int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif

cin >> n >> m;
for (int i = 1; i < n; i++) {
int x,y; scanf("%d%d",&x,&y);
v[x].push_back(y); v[y].push_back(x);
}
clo = 0; L[1] = 1; dfs(1);

while (m--) {
int p,k; LL ans; scanf("%d%d",&p,&k);
if (L[p] - k >= 1) ans = 1LL*k*1LL*siz[p];
else ans = 1LL*(L[p]-1)*1LL*siz[p];
if (dfi[p] + 1 <= dfo[p]) ans += query(1,1,n,dfi[p]+1,dfo[p],L[p] + 1,L[p] + k);
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: