IOI2011 Race [点分治]

题意

  给一棵树,每条边有权。求一条简单路径,权值和等于 $K$,且边的数量最小。


  点分治,求距离时带上经过边的数量即可。用的第一种写法(下面)。


食用淀粉质注意事项

1、 统计子树内答案的两种写法: 跟树形dp一样将某子树与前面的子树合并   或者是   考虑所有子树的答案再容斥,减去不合法的一棵子树内答案。

2、好好写求重心,千万不要写假!!!假淀粉害死人

  注意每次遍历先初始化$f[x]=0$,要有子树大小$S$。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N=200010;
 6 const int M=1000010;
 7 const int inf=0x3f3f3f3f;
 8 int n,k,x,y,z,rt,f[N],size[N],ans=inf,S;
 9 int dis[N],d[N],his[N],h[N],rec[M],t[N];
10 bool vis[N];
11 int head[N],to[N<<1],nxt[N<<1],w[N<<1],p;
12 inline int read() {
13     int re=0; char ch=getchar();
14     while (ch<'0'||ch>'9') ch=getchar();
15     while (ch>='0'&&ch<='9') re=re*10+ch-48,ch=getchar();
16     return re;
17 }
18 inline void add(int x,int y,int z) {
19     to[++p]=y; nxt[p]=head[x]; w[p]=z; head[x]=p;
20     to[++p]=x; nxt[p]=head[y]; w[p]=z; head[y]=p;
21 }
22 void get_rt(int x,int fa) {
23     size[x]=1; f[x]=0;//here
24     for (int i=head[x]; i; i=nxt[i]) {
25         if (to[i]==fa || vis[to[i]]) continue;
26         get_rt(to[i],x);
27         size[x]+=size[to[i]];
28         if (size[to[i]]>f[x]) f[x]=size[to[i]];
29     }
30     f[x]=max(f[x],S-size[x]);//here
31     if (f[x]<f[rt]) rt=x;
32 }
33 void get_dis(int x,int fa) {
34     if (d[x]<=k) dis[++dis[0]]=d[x],his[dis[0]]=h[x];
35     for (int i=head[x]; i; i=nxt[i]) {
36         if (to[i]==fa || vis[to[i]]) continue;
37         d[to[i]]=d[x]+w[i]; h[to[i]]=h[x]+1;
38         if (d[to[i]]<=k) get_dis(to[i],x);
39     }
40 }
41 void dfs(int x) {
42     vis[x]=1; int T=0;
43     for (int i=head[x]; i; i=nxt[i]) {
44         if (vis[to[i]]) continue;
45         dis[0]=0; d[to[i]]=w[i],h[to[i]]=1; get_dis(to[i],x);
46         for (int i=1; i<=dis[0]; i++) 
47             if (~rec[k-dis[i]]) ans=min(ans,his[i]+rec[k-dis[i]]); 
48         for (int i=1; i<=dis[0]; i++) 
49             t[++T]=dis[i],rec[dis[i]]=~rec[dis[i]] ? min(rec[dis[i]],his[i]):his[i];
50     }
51     while (T) rec[t[T--]]=-1;
52     for (int i=head[x]; i; i=nxt[i]) {
53         if (vis[to[i]]) continue;
54         S=size[to[i]]; f[rt=0]=inf;
55         get_rt(to[i],x); dfs(rt);
56     }
57 }
58 int main() {
59     n=read(); k=read();
60     for (int i=1; i<n; i++) x=read()+1,y=read()+1,z=read(),add(x,y,z);
61     memset(rec,-1,sizeof rec); rec[0]=0;
62     S=n; f[rt=0]=inf;
63     get_rt(1,0); dfs(rt);
64     printf("%d\n",ans==inf ? -1:ans);
65     return 0;
66 }

猜你喜欢

转载自www.cnblogs.com/hnooo/p/10125494.html