这题真神了……没想到链的问题还可以转化为子树解……一开始总以为是树链剖分……

我们可以先把问题转化为每条边只能被一个工人修复一次,可以证明这样答案不会更优也不会更差

设f[i]表示覆盖了i节点子树的所有边都被覆盖且i的父向边也被覆盖的最小花费

我们可以把工人修复转化为“头加尾减”,即在u[i]处添加i个工人并在v[i]处删除这个工人

这样我们对每个节点添加的工人工人维护dfs序,这样我们从下往上更新即可

(注意中间计算不要爆long long)

  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\n",f[1]);
138 }
View Code

 

posted on 2017-01-28 23:47  acphile  阅读(464)  评论(0)    收藏  举报