您的位置:首页 > 其它

bzoj1468 Tree

2016-06-25 11:03 381 查看
最经典的点分治题目,在递归子树的时候减去在算父亲时的不合法方案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 40005
using namespace std;
struct Node{
int to,next,v;
}e[N<<1];
int sum,rt,n,k,head
,tot,cnt,mx
,sz
,tmp
,ans;
bool vis
;
void add(int x,int y,int z){
e[++tot]=(Node){y,head[x],z};head[x]=tot;
e[++tot]=(Node){x,head[y],z};head[y]=tot;
}
void getroot(int x,int fa){
mx[x]=0;sz[x]=1;
for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa&&!vis[e[i].to]){
getroot(e[i].to,x);
sz[x]+=sz[e[i].to];
mx[x]=max(mx[x],sz[e[i].to]);
}mx[x]=max(mx[x],sum-sz[x]);
if(mx[x]<mx[rt])rt=x;
}
void getdis(int x,int fa,int d){
tmp[++cnt]=d;
for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa&&!vis[e[i].to]){
getdis(e[i].to,x,d+e[i].v);
}
}
void calc(int x,int dis,int type){
cnt=0;
getdis(x,0,0);
sort(tmp+1,tmp+1+cnt);
int l=1,r=cnt;
while(l<=r){
while(tmp[l]+tmp[r]>dis)r--;
if(l>r)break;
ans+=(r-l)*type;l++;
}
}
void work(int x){
vis[x]=1;
calc(x,k,1);
for(int i=head[x];i;i=e[i].next)if(!vis[e[i].to]){
calc(e[i].to,k-e[i].v*2,-1);
sum=sz[e[i].to];rt=0;
getroot(e[i].to,0);
work(rt);
}
}
int main(){
//  freopen("test.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
scanf("%d",&k);
sum=mx[0]=n;rt=0;ans=0;
getroot(1,0);
work(rt);
printf("%d\n",ans);
}


View Code

1468: Tree

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1099 Solved: 581
[Submit][Status][Discuss]

Description

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

Input

N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

Output

一行,有多少对点之间的距离小于等于k

Sample Input

7

1 6 13

6 3 9

3 5 7

4 1 3

2 4 20

4 7 2

10

Sample Output

5
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: