Bzoj2599 [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
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

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
",ans);
112     else printf("-1
");
113     return 0;
114 }
原文地址:https://www.cnblogs.com/SilverNebula/p/6418846.html