Bzoj2599 [IOI2011]Race
Submit: 3200 Solved: 938
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
HINT
Source
点分治
人比较蠢,刚开始的写法是分治时把管辖范围内所有的点丢进一个数组,按距离排序,然后用两个指针前后夹逼……很明显是错的
接着换成开一个数组tmp[i]记录距离根为i的点的最小深度,看上去没什么问题。然而像我在85行的注释那样写,直接从树根开始统计,就很明显是错的了(不能保证找到的两点之间路径经过根)
接着换成了现在的写法,19s龟速AC。放弃卡常。
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=200010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{ 17 int v,nxt,w; 18 }e[mxn<<1]; 19 int hd[mxn],mct=0; 20 void add_edge(int u,int v,int w){ 21 e[++mct].v=v;e[mct].w=w;e[mct].nxt=hd[u];hd[u]=mct;return; 22 } 23 int n,k,rt; 24 int mc[mxn],mini,sum; 25 int tmp[1000010],cnt; 26 int dep[mxn],dis[mxn],sz[mxn]; 27 int ans; 28 bool vis[mxn]; 29 void DFS_sz(int u,int fa){ 30 sz[u]=1;mc[u]=0; 31 for(int i=hd[u];i;i=e[i].nxt){ 32 int v=e[i].v; 33 if( vis[v] || v==fa)continue; 34 DFS_sz(v,u); 35 sz[u]+=sz[v]; 36 mc[u]=max(mc[u],sz[v]); 37 } 38 mc[u]=max(mc[u],sum-sz[u]); 39 if(mini>mc[u]){mini=mc[u];rt=u;} 40 return; 41 } 42 void DFS2(int u,int fa,bool mode){ 43 if(dep[u]>ans)return; 44 if(dis[u]<=k){ 45 if(mode)tmp[dis[u]]=min(tmp[dis[u]],dep[u]); 46 else tmp[dis[u]]=1e8; 47 } 48 for(int i=hd[u];i;i=e[i].nxt){ 49 int v=e[i].v; 50 if(vis[v] || v==fa)continue; 51 DFS2(v,u,mode); 52 } 53 return; 54 } 55 void calc(int x,int fa){ 56 dep[x]=dep[fa]+1; 57 if(dis[x]<=k){ans=min(ans,dep[x]+tmp[k-dis[x]]);} 58 for(int i=hd[x];i;i=e[i].nxt){ 59 int v=e[i].v; 60 if(vis[v] || v==fa)continue; 61 dis[v]=dis[x]+e[i].w; 62 calc(v,x); 63 } 64 return; 65 } 66 void solve(int x){ 67 vis[x]=1; 68 // dis[x]=0; 69 tmp[0]=0; 70 // dep[0]=-1; 71 dep[x]=0; 72 for(int i=hd[x];i;i=e[i].nxt){ 73 int v=e[i].v; 74 if(!vis[v]){ 75 dis[v]=e[i].w; 76 calc(v,x); 77 DFS2(v,x,1); 78 } 79 } 80 for(int i=hd[x];i;i=e[i].nxt){ 81 int v=e[i].v; 82 if(!vis[v]){DFS2(v,x,0);} 83 } 84 // DFS2(x,0,1); 85 // calc(x,0); 86 // DFS2(x,0,0); 87 for(int i=hd[x];i;i=e[i].nxt){ 88 int v=e[i].v; 89 if(vis[v])continue; 90 mini=1e8;rt=0; 91 sum=sz[v]; 92 DFS_sz(v,0); 93 solve(rt); 94 } 95 return; 96 } 97 int main(){ 98 int i,j,u,v,w; 99 n=read();k=read(); 100 for(i=1;i<n;i++){ 101 u=read()+1;v=read()+1;w=read(); 102 add_edge(u,v,w); 103 add_edge(v,u,w); 104 } 105 memset(tmp,0x3f,sizeof tmp); 106 mc[rt=0]=1e8; 107 ans=mini=1e8; 108 sum=n; 109 DFS_sz(1,0); 110 solve(rt); 111 if(ans<=n)printf("%d\n",ans); 112 else printf("-1\n"); 113 return 0; 114 }
本文为博主原创文章,转载请注明出处。