1468: Tree
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
点分治,每次找到树的重心(重心两边的子树大小最接近),统计过重心的答案,再将重心断开,再在两个子树中统计答案,然后重复这一过程。
在这道题当中,我们需要找的是距离小于k的点对,我们可以将每个点到根的距离dfs出来,然后排序,那么我们要求的是就是ai+aj<k的总和,
我们注意到如果i是固定的,那么合法的j是一个区间,同时随着i的增长,j在减小,所以我们枚举i然后不断缩小j,然后就好了。
这时我们会发现我们统计到两个点在一个子树中但是最短路径不经过根的情况,那么我们就需要再次统计各个子树内部两个点对的距离加上子树的根到根的距离是否小于k即可,
如果小于就减去,那么我们会发现我们实际上只不过是给子树中的每个点的距离预先加上e[i].w,然后向上面统计答案即可(有点类似容斥)。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 40000+5 14 #define maxm 10000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 struct edge{ 24 int go,next,w; 25 }e[2*maxn]; 26 int ans,tot,sum,n,k,root,head[maxn],s[maxn],f[maxn],deep[maxn],d[maxn]; 27 bool v[maxn]; 28 int read(){ 29 int x=0,f=1;char ch=getchar(); 30 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 31 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 32 return x*f; 33 } 34 void insert(int x,int y,int z){ 35 e[++tot]=(edge){y,head[x],z};head[x]=tot; 36 e[++tot]=(edge){x,head[y],z};head[y]=tot; 37 } 38 void getroot(int x,int fa){ 39 s[x]=1;f[x]=0; 40 for4(i,x){ 41 if(v[y]||y==fa)continue ; 42 getroot(y,x); 43 s[x]+=s[y]; 44 f[x]=max(f[x],s[y]); 45 } 46 f[x]=max(f[x],sum-s[x]); 47 if(f[x]<f[root])root=x; 48 } 49 void getdeep(int x,int fa){ 50 deep[++deep[0]]=d[x]; 51 for4(i,x){ 52 if(v[y]||y==fa)continue ; 53 d[y]=d[x]+e[i].w; 54 getdeep(y,x); 55 } 56 } 57 int calc(int x,int now){ 58 deep[0]=0;d[x]=now; 59 getdeep(x,0); 60 sort(deep+1,deep+deep[0]+1); 61 int t=0; 62 for(int l=1,r=deep[0];l<r;) 63 if(deep[l]+deep[r]<=k){ 64 t+=r-l; 65 l++; 66 } 67 else r--; 68 return t; 69 } 70 void work(int x){ 71 v[x]=1; 72 ans+=calc(x,0); 73 for4(i,x){ 74 if(v[y])continue; 75 ans-=calc(y,e[i].w); 76 sum=s[y]; 77 root=0; 78 getroot(y,0); 79 work(root); 80 } 81 } 82 int main(){ 83 //freopen("input.txt","r",stdin); 84 //freopen("output.txt","w",stdout); 85 n=read(); 86 for1(i,n-1){ 87 int x=read(),y=read(),z=read(); 88 insert(x,y,z); 89 } 90 k=read(); 91 sum=n;f[root]=inf; 92 getroot(1,0); 93 work(root); 94 printf("%d\n",ans); 95 return 0; 96 }