2599: [IOI2011]Race
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 1401 Solved: 412
[Submit][Status]
Description
给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
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
题解:
居然1A了,还跑这么快233.。。。
有关树上路径我们可以考虑点分治。
假如我们当前正在处理以rt为根的树,那么路径统计的时候比较麻烦的就是在同一棵子树内的两个点。用g[i]表示达到i距离最小边数。
处理这个问题很简单,我们可以先用一棵子树的信息来更新答案,再用它的信息来更新我们的g数组。
就是这样,最后再做一遍还原即可。
inline void work(int x) { v[x]=1; for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) { cnt=0; getdep(y,x,e[i].w,1); for1(j,cnt)if(d[j][0]<=k)ans=min(ans,g[k-d[j][0]]+d[j][1]); for1(j,cnt)if(d[j][0]<=k)g[d[j][0]]=min(g[d[j][0]],d[j][1]); } ans=min(ans,g[k]); for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) { cnt=0; getdep(y,x,e[i].w,1); for1(j,cnt)if(d[j][0]<=k)g[d[j][0]]=inf; } for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) { sum=s[y];rt=0; getrt(y,x); work(rt); } }
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 200000+5 26 27 #define maxm 2000000+5 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline int read() 48 49 { 50 51 int x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 struct edge{int go,next,w;}e[2*maxn]; 61 int n,k,cnt,tot,sum,rt,ans=inf,f[maxn],g[maxm],d[maxn][2],head[maxn],s[maxn]; 62 bool v[maxn]; 63 inline void insert(int x,int y,int z) 64 { 65 e[++tot]=(edge){y,head[x],z};head[x]=tot; 66 e[++tot]=(edge){x,head[y],z};head[y]=tot; 67 } 68 inline void getrt(int x,int fa) 69 { 70 s[x]=1;f[x]=0; 71 for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]&&y!=fa) 72 { 73 getrt(y,x); 74 s[x]+=s[y]; 75 f[x]=max(f[x],s[y]); 76 } 77 f[x]=max(f[x],sum-f[x]); 78 if(f[x]<f[rt])rt=x; 79 } 80 inline void getdep(int x,int fa,int w1,int w2) 81 { 82 d[++cnt][0]=w1;d[cnt][1]=w2; 83 for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]&&y!=fa)getdep(y,x,w1+e[i].w,w2+1); 84 } 85 inline void work(int x) 86 { 87 v[x]=1; 88 for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) 89 { 90 cnt=0; 91 getdep(y,x,e[i].w,1); 92 for1(j,cnt)if(d[j][0]<=k)ans=min(ans,g[k-d[j][0]]+d[j][1]); 93 for1(j,cnt)if(d[j][0]<=k)g[d[j][0]]=min(g[d[j][0]],d[j][1]); 94 } 95 ans=min(ans,g[k]); 96 for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) 97 { 98 cnt=0; 99 getdep(y,x,e[i].w,1); 100 for1(j,cnt)if(d[j][0]<=k)g[d[j][0]]=inf; 101 } 102 for(int i=head[x],y;i;i=e[i].next)if(!v[y=e[i].go]) 103 { 104 sum=s[y];rt=0; 105 getrt(y,x); 106 work(rt); 107 } 108 } 109 110 int main() 111 112 { 113 114 freopen("input.txt","r",stdin); 115 116 freopen("output.txt","w",stdout); 117 118 n=read();k=read(); 119 for0(i,k)g[i]=inf; 120 for1(i,n-1) 121 { 122 int x=read()+1,y=read()+1,z=read();insert(x,y,z); 123 } 124 f[rt=0]=inf; 125 sum=n; 126 getrt(1,0); 127 work(rt); 128 if(ans>=n)ans=-1; 129 cout<<ans<<endl; 130 131 return 0; 132 133 }