2599: [IOI2011]Race
Description
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
0 1 1
1 2 2
1 3 4
Sample Output
2
点分治来求就好了,平常我们做点分治的时候要去除在子树中的情况,
这道题怎么去呢?好像不好去。。。那么就不去了。。。
因为我们想一下,如果答案被子树中的两个点更新了,那么,答案一定多加了一个重复的距离,
那当我们分治下去的时候就会发现,一定可以以更优的答案来更新掉当前答案,这样就好了。
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 200000+5 14 #define maxm 2000000+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 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 struct edge{ 30 int go,next,w; 31 }e[2*maxn]; 32 int n,k,cnt,tot,sum,rt,ans=inf,f[maxn],g[maxm],d[maxn][2],head[maxn],s[maxn]; 33 bool v[maxn]; 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){ 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-f[x]); 47 if(f[x]<f[rt])rt=x; 48 } 49 void getdeep(int x,int fa,int w1,int w2){ 50 d[++cnt][0]=w1;d[cnt][1]=w2; 51 for4(i,x) 52 if(!v[y]&&y!=fa) 53 getdeep(y,x,w1+e[i].w,w2+1); 54 } 55 void work(int x){ 56 v[x]=1; 57 for4(i,x) 58 if(!v[y]){ 59 cnt=0; 60 getdeep(y,x,e[i].w,1); 61 for1(j,cnt) 62 if(d[j][0]<=k)ans=min(ans,g[k-d[j][0]]+d[j][1]); 63 for1(j,cnt) 64 if(d[j][0]<=k)g[d[j][0]]=min(g[d[j][0]],d[j][1]); 65 } 66 ans=min(ans,g[k]); 67 for4(i,x) 68 if(!v[y]){ 69 cnt=0; 70 getdeep(y,x,e[i].w,1); 71 for1(j,cnt) 72 if(d[j][0]<=k) 73 g[d[j][0]]=inf; 74 } 75 for4(i,x) 76 if(!v[y]){ 77 sum=s[y];rt=0; 78 getroot(y,x); 79 work(rt); 80 } 81 } 82 int main(){ 83 //freopen("input.txt","r",stdin); 84 //freopen("output.txt","w",stdout); 85 n=read();k=read(); 86 for0(i,k)g[i]=inf; 87 for1(i,n-1){ 88 int x=read()+1,y=read()+1,z=read();insert(x,y,z); 89 } 90 f[rt=0]=inf; 91 sum=n; 92 getroot(1,0); 93 work(rt); 94 if(ans>=n)ans=-1; 95 cout<<ans<<endl; 96 return 0; 97 }
ps:这让我想到一道并查集的题。。。http://www.cnblogs.com/htwx/articles/4782458.html