最经典的点分治题目,在递归子树的时候减去在算父亲时的不合法方案。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 #include<cmath> 7 #define ll long long 8 #define N 40005 9 using namespace std; 10 struct Node{ 11 int to,next,v; 12 }e[N<<1]; 13 int sum,rt,n,k,head[N],tot,cnt,mx[N],sz[N],tmp[N],ans; 14 bool vis[N]; 15 void add(int x,int y,int z){ 16 e[++tot]=(Node){y,head[x],z};head[x]=tot; 17 e[++tot]=(Node){x,head[y],z};head[y]=tot; 18 } 19 void getroot(int x,int fa){ 20 mx[x]=0;sz[x]=1; 21 for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa&&!vis[e[i].to]){ 22 getroot(e[i].to,x); 23 sz[x]+=sz[e[i].to]; 24 mx[x]=max(mx[x],sz[e[i].to]); 25 }mx[x]=max(mx[x],sum-sz[x]); 26 if(mx[x]<mx[rt])rt=x; 27 } 28 void getdis(int x,int fa,int d){ 29 tmp[++cnt]=d; 30 for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa&&!vis[e[i].to]){ 31 getdis(e[i].to,x,d+e[i].v); 32 } 33 } 34 void calc(int x,int dis,int type){ 35 cnt=0; 36 getdis(x,0,0); 37 sort(tmp+1,tmp+1+cnt); 38 int l=1,r=cnt; 39 while(l<=r){ 40 while(tmp[l]+tmp[r]>dis)r--; 41 if(l>r)break; 42 ans+=(r-l)*type;l++; 43 } 44 } 45 void work(int x){ 46 vis[x]=1; 47 calc(x,k,1); 48 for(int i=head[x];i;i=e[i].next)if(!vis[e[i].to]){ 49 calc(e[i].to,k-e[i].v*2,-1); 50 sum=sz[e[i].to];rt=0; 51 getroot(e[i].to,0); 52 work(rt); 53 } 54 } 55 int main(){ 56 // freopen("test.in","r",stdin); 57 scanf("%d",&n); 58 for(int i=1;i<n;i++){ 59 int x,y,z;scanf("%d%d%d",&x,&y,&z); 60 add(x,y,z); 61 } 62 scanf("%d",&k); 63 sum=mx[0]=n;rt=0;ans=0; 64 getroot(1,0); 65 work(rt); 66 printf("%d\n",ans); 67 }
1468: Tree
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10
Sample Output
5