[poj 1741]Treeツリー上の点治
タイトル:http://poj.org/problem?id=1741 Tree Time Limit:1000 MS Memory Limit:30000 K Total Submissions:16555 Acctepted:5396
Description Givivive Give Givive Greption Give Gregth(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give a n integer k,forevrypair( u,v)of extrexclexclinininininininininininininininindedededededededededededededededeaaaaaaaattttttttttttttttttcacacacacacacall(u))aaaaaaaaaaaaaaaaaaaaaaaaaawhich are valid for a given tree.
Input The input contains several test cases.The first line of each test case contains two integers n,k.(n==10000)The follwing n-1 line each containe integers u,v,l,which means there is.edgement。
Output For each test case output the answer on a single line.
Sample Input
5 4 1 2 3 1 3 1 1 4 3 5 1 0
Sample Output
8は意味を書きます:1株の辺に権力の木を持って、2時の間の距離がKに等しいことより小さいことを聞きます。
考え方:第一点分治。。。。dfs+列挙の複雑さn^2は受け入れられません。ツリーの特徴によってポイントを分けます。O(nlon^2)nlog nは、各サブツリーのルートを通るスキームの数を計算します。すなわち、サブツリーのnowからすべての点jまでの経路長dis[j]、*lognのソート統計を求める。
1.各ソロ(x)については、x子樹の重心を扱うので、最大logn層(重心dfsは最大子樹ノードの個数を求めます。)
2.cal(x)は答えを統計して、x子樹の中でdis[x]+dix[y]<=Kの方案数を満たします。cal(x)で処理されているのは、異なるサブツリーを経ているのではなく、from【i】とfrom【j】が等しいかもしれないので、計算を繰り返したので、ans-cal(サブツリーx(K−=dis【x】【サブツリーx】)の和;
コード:
Description Givivive Give Givive Greption Give Gregth(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give a n integer k,forevrypair( u,v)of extrexclexclinininininininininininininininindedededededededededededededededeaaaaaaaattttttttttttttttttcacacacacacacall(u))aaaaaaaaaaaaaaaaaaaaaaaaaawhich are valid for a given tree.
Input The input contains several test cases.The first line of each test case contains two integers n,k.(n==10000)The follwing n-1 line each containe integers u,v,l,which means there is.edgement。
Output For each test case output the answer on a single line.
Sample Input
5 4 1 2 3 1 3 1 1 4 3 5 1 0
Sample Output
8は意味を書きます:1株の辺に権力の木を持って、2時の間の距離がKに等しいことより小さいことを聞きます。
考え方:第一点分治。。。。dfs+列挙の複雑さn^2は受け入れられません。ツリーの特徴によってポイントを分けます。O(nlon^2)nlog nは、各サブツリーのルートを通るスキームの数を計算します。すなわち、サブツリーのnowからすべての点jまでの経路長dis[j]、*lognのソート統計を求める。
1.各ソロ(x)については、x子樹の重心を扱うので、最大logn層(重心dfsは最大子樹ノードの個数を求めます。)
2.cal(x)は答えを統計して、x子樹の中でdis[x]+dix[y]<=Kの方案数を満たします。cal(x)で処理されているのは、異なるサブツリーを経ているのではなく、from【i】とfrom【j】が等しいかもしれないので、計算を繰り返したので、ans-cal(サブツリーx(K−=dis【x】【サブツリーx】)の和;
コード:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#define N 10005
using namespace std;
struct node{
int x,y;
node(int xx,int yy)
{
x=xx,y=yy;
}
};
vector<node> lin[N];
vector<int> d;
int sz[N],f[N];//sz[x]-->x ,f[x]-->x ;
int n;
int rt;
int vis[N],dis[N];
int K;
int ans,size;
int aa,bb,cc;
void getrt(int x,int fa)// *sz,*f
{
sz[x]=1;
f[x]=0;
for(int i=0;i<lin[x].size();i++)
{
int u=lin[x][i].x;
if(vis[u]||u==fa) continue;
getrt(u,x);
sz[x]+=sz[u];
f[x]=max(sz[u],f[x]);
}
f[x]=max(f[x],size-sz[x]);//! x =max( -f[x],f[x])
if(f[x]<f[rt]) rt=x;
}
void getdis(int x,int fa)// dfs + sz[x], size
{
sz[x]=1;
d.push_back(dis[x]);
for(int i=0;i<lin[x].size();i++)
{
int u=lin[x][i].x;
if(vis[u]||u==fa) continue;
dis[u]=dis[x]+lin[x][i].y;
getdis(u,x);
sz[x]+=sz[u];
}
}
int cal(int x,int y)
{
int ret=0;
d.clear();
dis[x]=y;
getdis(x,0);
sort(d.begin(),d.end());
int l=0;
int r=d.size()-1;
while(l<r)
{
while(d[l]+d[r]>K&l<r) r--;
ret+=r-l;
l++;
}
return ret;
}
void solve(int x)
{
//cout<<x<<endl;
ans+=cal(x,0);
vis[x]=1;
for(int i=0;i<lin[x].size();i++)
{
int u=lin[x][i].x;
if(vis[u]) continue;
ans-=cal(u,lin[x][i].y);
f[0]=size=sz[u];//!!! getdis
getrt(u,rt=0);
solve(rt);
}
}
int main()
{
while(scanf("%d%d",&n,&K))
{
if(!n&&!K) return 0;
for(int i=1;i<=n;i++)
{
vis[i]=0;
lin[i].clear();
}
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&aa,&bb,&cc);
lin[aa].push_back(node(bb,cc));
lin[bb].push_back(node(aa,cc));
}
ans=0;
f[0]=size=n;
getrt(1,rt=0);
solve(rt);
printf("%d
",ans);
}
}