题意:给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.
N <= 200000, K <= 1000000
思路:跟着高中学长李日天(迪克李)的课件复习一下树分治
https://wenku.baidu.com/view/ae220cc0ed630b1c58eeb5b3.html
也算是自己第一道独立完成的点分治,纪念一下
From https://www.cnblogs.com/candy99/p/6270581.html
目前遇到的点分治处理有两种:
1.先统计每颗子树,处理一颗子树时使用了之前子树的信息
2.先统计整棵树然后减去同一棵子树里的,可以只一遍邻接链表循环
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second s 19 #define MP make_pair 20 #define N 410000 21 #define M 1100000 22 #define MOD 1000000007 23 #define eps 1e-8 24 #define pi acos(-1) 25 #define oo 1e9 26 27 int q[N][2],head[N],vet[N],nxt[N],len[N],dis[N],dep[N],flag[N],son[N],c[N], 28 f[M],n,tot,top,ans,sum,root,K; 29 30 31 32 int read() 33 { 34 int v=0,f=1; 35 char c=getchar(); 36 while(c<48||57<c) {if(c==‘-‘) f=-1; c=getchar();} 37 while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar(); 38 return v*f; 39 } 40 41 void add(int a,int b,int c) 42 { 43 nxt[++tot]=head[a]; 44 vet[tot]=b; 45 len[tot]=c; 46 head[a]=tot; 47 } 48 49 void getroot(int u,int fa) 50 { 51 son[u]=1; c[u]=0; 52 int e=head[u]; 53 while(e) 54 { 55 int v=vet[e]; 56 if(v!=fa&&!flag[v]) 57 { 58 getroot(v,u); 59 son[u]+=son[v]; 60 c[u]=max(c[u],son[v]); 61 } 62 e=nxt[e]; 63 } 64 c[u]=max(c[u],sum-c[u]); 65 if(c[u]<c[root]) root=u; 66 } 67 68 void dfs(int u,int fa) 69 { 70 q[++top][1]=dis[u]; 71 q[top][2]=dep[u]; 72 int e=head[u]; 73 while(e) 74 { 75 int v=vet[e]; 76 if(v!=fa&&!flag[v]) 77 { 78 dep[v]=dep[u]+1; 79 dis[v]=dis[u]+len[e]; 80 dfs(v,u); 81 } 82 e=nxt[e]; 83 } 84 } 85 86 void work(int u) 87 { 88 flag[u]=1; f[0]=0; dep[u]=1; 89 int e=head[u]; 90 while(e) 91 { 92 int v=vet[e]; 93 if(!flag[v]) 94 { 95 top=0; 96 dis[v]=len[e]; 97 dep[v]=1; 98 dfs(v,u); 99 for(int i=1;i<=top;i++) 100 { 101 int t=K-q[i][1]; 102 if(t>=0&&t<=K) ans=min(ans,q[i][2]+f[t]); 103 } 104 ans=min(ans,f[K]); 105 for(int i=1;i<=top;i++) 106 if(q[i][1]>=0&&q[i][1]<=K) f[q[i][1]]=min(f[q[i][1]],q[i][2]); 107 } 108 e=nxt[e]; 109 } 110 111 e=head[u]; 112 while(e) 113 { 114 int v=vet[e]; 115 if(!flag[v]) 116 { 117 top=0; 118 dis[v]=len[e]; 119 dep[v]=1; 120 dfs(v,u); 121 for(int i=1;i<=top;i++) 122 if(q[i][1]>=0&&q[i][1]<=K) f[q[i][1]]=oo; 123 } 124 e=nxt[e]; 125 } 126 127 e=head[u]; 128 while(e) 129 { 130 int v=vet[e]; 131 if(!flag[v]) 132 { 133 sum=son[v]; root=0; 134 getroot(v,0); 135 work(root); 136 } 137 e=nxt[e]; 138 } 139 } 140 141 int main() 142 { 143 //freopen("bzoj2599.in","r",stdin); 144 //freopen("bzoj2599.out","w",stdout); 145 scanf("%d%d",&n,&K); 146 for(int i=1;i<=n-1;i++) 147 { 148 int x,y,z; 149 scanf("%d%d%d",&x,&y,&z); 150 x++; y++; 151 add(x,y,z); 152 add(y,x,z); 153 } 154 root=0; sum=n; c[0]=n; 155 ans=oo; 156 for(int i=0;i<=K;i++) f[i]=oo; 157 getroot(1,0); 158 work(root); 159 if(ans>n) printf("-1\n"); 160 else printf("%d\n",ans); 161 return 0; 162 } 163 164 165 166 167 168
原文:https://www.cnblogs.com/myx12345/p/9710738.html