这题真神了……没想到链的问题还可以转化为子树解……一开始总以为是树链剖分……
我们可以先把问题转化为每条边只能被一个工人修复一次,可以证明这样答案不会更优也不会更差
设f[i]表示覆盖了i节点子树的所有边都被覆盖且i的父向边也被覆盖的最小花费
我们可以把工人修复转化为“头加尾减”,即在u[i]处添加i个工人并在v[i]处删除这个工人
这样我们对每个节点添加的工人工人维护dfs序,这样我们从下往上更新即可
(注意中间计算不要爆long long)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 int l[300010],r[300010],b[300010],c[300010],fa[300010],n,m,t; 6 ll f[300010],tr[300010*4],laz[300010*4]; 7 vector<int> g[300010],w[300010],d[300010]; 8 9 const ll inf=1000000000000007ll; 10 void inc(ll &x,ll y) 11 { 12 x+=y; 13 if (x>inf) x=inf; 14 } 15 16 void push(int i) 17 { 18 inc(laz[i*2],laz[i]); 19 inc(laz[i*2+1],laz[i]); 20 inc(tr[i*2],laz[i]); 21 inc(tr[i*2+1],laz[i]); 22 laz[i]=0; 23 } 24 25 void change(int i,int l,int r,int x,ll y) 26 { 27 if (l==r) tr[i]=y; 28 else { 29 int m=(l+r)>>1; 30 if (laz[i]) push(i); 31 if (x<=m) change(i*2,l,m,x,y); 32 else change(i*2+1,m+1,r,x,y); 33 tr[i]=min(tr[i*2],tr[i*2+1]); 34 } 35 } 36 37 void add(int i,int l,int r,int x,int y,ll z) 38 { 39 if (x<=l&&y>=r) 40 { 41 inc(tr[i],z); 42 inc(laz[i],z); 43 } 44 else { 45 int m=(l+r)>>1; 46 if (laz[i]) push(i); 47 if (x<=m) add(i*2,l,m,x,y,z); 48 if (y>m) add(i*2+1,m+1,r,x,y,z); 49 tr[i]=min(tr[i*2],tr[i*2+1]); 50 } 51 } 52 53 ll ask(int i,int l,int r,int x,int y) 54 { 55 if (x>y) return inf; 56 if (x<=l&&y>=r) return tr[i]; 57 else { 58 int m=(l+r)>>1; 59 ll s=inf; 60 if (laz[i]) push(i); 61 if (x<=m) s=min(s,ask(i*2,l,m,x,y)); 62 if (y>m) s=min(s,ask(i*2+1,m+1,r,x,y)); 63 return s; 64 } 65 } 66 67 68 void dfs(int x) 69 { 70 l[x]=t+1; 71 for (int i=0; i<w[x].size(); i++) b[w[x][i]]=++t; 72 for (int i=0; i<g[x].size(); i++) 73 { 74 int y=g[x][i]; 75 if (fa[x]!=y) 76 { 77 fa[y]=x; 78 dfs(y); 79 } 80 } 81 r[x]=t; 82 } 83 84 void dp(int x) 85 { 86 ll s=0; 87 for (int i=0; i<g[x].size(); i++) 88 { 89 int y=g[x][i]; 90 if (y!=fa[x]) 91 { 92 dp(y); 93 inc(s,f[y]); 94 } 95 } 96 if (x==1) {f[1]=s; return;} 97 for (int i=0; i<w[x].size(); i++) 98 { 99 int y=w[x][i]; 100 change(1,1,m,b[y],s+(ll)c[y]); 101 } 102 for (int i=0; i<d[x].size(); i++) 103 { 104 int y=d[x][i]; 105 change(1,1,m,b[y],inf); 106 } 107 for (int i=0; i<g[x].size(); i++) 108 { 109 int y=g[x][i]; 110 if (fa[x]!=y) 111 add(1,1,m,l[y],r[y],s-f[y]); 112 } 113 f[x]=ask(1,1,m,l[x],r[x]); 114 } 115 116 117 int main() 118 { 119 scanf("%d%d",&n,&m); 120 for (int i=1; i<n; i++) 121 { 122 int x,y; 123 scanf("%d%d",&x,&y); 124 g[x].push_back(y); 125 g[y].push_back(x); 126 } 127 for (int i=1; i<=4*m; i++) {tr[i]=inf;laz[i]=0;} 128 for (int i=1; i<=m; i++) 129 { 130 int x,y; 131 scanf("%d%d%d",&x,&y,&c[i]); 132 w[x].push_back(i); 133 d[y].push_back(i); 134 } 135 t=0; dfs(1); 136 dp(1); 137 if (f[1]>=inf) puts("-1"); else printf("%lld ",f[1]); 138 }