[loj574]黄金矿工
记$dep_{x}$为1到$x$的边权和,当$x$上的矿工挖了$y$上的黄金时($y$在$x$子树内),显然$\sum_{e}c_{e}=dep_{y}-dep_{x}$
由此,对于$u$上权值为$v$的矿工(或黄金),不妨修改其权值为$v-dep_{x}$(或$v+dep_{x}$)
此时,矿工挖黄金的收益即两者的权值和(同时黄金要在矿工子树内),因此我们仅关心于挖了黄金的矿工和被挖的黄金,而不关心具体谁挖了谁
根据Hall定理,当选择了若干个黄金和矿工后,判断是否合法仅需要保证:
1.选择的矿工数等于黄金数
2.令$\Delta_{i}$表示$i$子树内选择的黄金数量-矿工的数量,要求$\forall 1\le i\le n,\Delta_{i}\ge 0$
一个技巧:在选择$u$上一个权值为$v$的矿工(或黄金)时,直接将该矿工(或黄金)删除,并在$u$上增加一个权值为$-v$的黄金(或矿工),即可用选择来代替撤销,因此以下不考虑撤销的操作
由于一个节点上会有多个矿工和黄金,对两者分别维护一个set(可重),并只需要将set中的最大值作为”该点上的矿工(或黄金)“即可
下面,对加入矿工和加入黄金的操作分别讨论:
1.当在$u$上插入一个权值为$v$的矿工,不妨先选择这个矿工,为了保持数量一致,即需要再选择一个黄金
(由于本来的方案是最优的,显然对其他矿工或黄金调整都会与此矛盾)
很显然,只需要对$u$到根路径上所有$\Delta_{i}$减少1,并找到其中第一个(最深的)$i$满足$\Delta_{i}=-1$,在$i$的子树内选择权值最大的黄金即可
用树链剖分+线段树维护$\Delta_{i}$,用线段树维护子树内权值最大的黄金,复杂度为$o(\log^{2}n)$
2.当在$u$上插入一个权值为$v$的黄金,同理先选择这个黄金,然后再选择一个矿工
考虑在每一个节点$u$上,用set维护$u$轻儿子子树内或$v=u$的节点$v$上矿工的权值,满足$v$到$u$路径上$\Delta_{i}\ge 1$,并用树链剖分+线段树维护这个set的最大值
考虑维护,即对每一条重链,将重链合法的前缀(即找到最浅的$\Delta_{i}$满足$\Delta_{i}\le 0$,从$i$的父亲到重链顶端)中(set的最大值)的最大值加入到重链顶端节点的父亲节点上
考虑维护,在每一次$x$上的权值或$x$到根的$\Delta$时,就将$x$到根路径上$x$的影响全部删除,修改后再加入(并且也不一定要判定是$x$的影响)
总复杂度为$o(n\log^{2}n)$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define oo 0x3f3f3f3f 5 #define ll long long 6 #define pii pair<int,int> 7 #define L (k<<1) 8 #define R (L+1) 9 #define mid (l+r>>1) 10 struct Edge{ 11 int nex,to,len; 12 }edge[N<<1]; 13 multiset<int>s[2][N]; 14 multiset<pair<int,int> >S[N]; 15 pair<int,int>mxf[2][N<<2]; 16 int E,n,m,p,x,y,z,head[N],fa[N],sz[N],dep[N],mx[N],dfn[N],idfn[N],top[N],leaf[N]; 17 int tag[N<<2],mnf[N<<2]; 18 ll ans; 19 void upd(int k,int x){ 20 tag[k]+=x; 21 mnf[k]+=x; 22 } 23 void down(int k){ 24 upd(L,tag[k]); 25 upd(R,tag[k]); 26 tag[k]=0; 27 } 28 void build(int k,int l,int r){ 29 mxf[0][k]=mxf[1][k]=make_pair(-oo,0); 30 if (l==r)return; 31 build(L,l,mid); 32 build(R,mid+1,r); 33 } 34 void update_Delta(int k,int l,int r,int x,int y,int z){ 35 if ((l>y)||(x>r))return; 36 if ((x<=l)&&(r<=y)){ 37 upd(k,z); 38 return; 39 } 40 down(k); 41 update_Delta(L,l,mid,x,y,z); 42 update_Delta(R,mid+1,r,x,y,z); 43 mnf[k]=min(mnf[L],mnf[R]); 44 } 45 void update_val(int p,int k,int l,int r,int x,pii y){ 46 if (l==r){ 47 mxf[p][k]=y; 48 return; 49 } 50 if (x<=mid)update_val(p,L,l,mid,x,y); 51 else update_val(p,R,mid+1,r,x,y); 52 mxf[p][k]=max(mxf[p][L],mxf[p][R]); 53 } 54 int query_first(int k,int l,int r,int x,int y){ 55 if ((l>y)||(x>r)||(mnf[k]>=1))return 0; 56 if (l==r)return l; 57 down(k); 58 int ans=query_first(L,l,mid,x,y); 59 if (ans)return ans; 60 return query_first(R,mid+1,r,x,y); 61 } 62 int query_last(int k,int l,int r,int x,int y){ 63 if ((l>y)||(x>r)||(mnf[k]>=0))return 0; 64 if (l==r)return l; 65 down(k); 66 int ans=query_last(R,mid+1,r,x,y); 67 if (ans)return ans; 68 return query_last(L,l,mid,x,y); 69 } 70 pii query_max(int p,int k,int l,int r,int x,int y){ 71 if ((l>y)||(x>r))return make_pair(-oo,0); 72 if ((x<=l)&&(r<=y))return mxf[p][k]; 73 return max(query_max(p,L,l,mid,x,y),query_max(p,R,mid+1,r,x,y)); 74 } 75 void update_Delta(int k,int p){ 76 while (k){ 77 update_Delta(1,1,n,dfn[top[k]],dfn[k],p); 78 k=fa[top[k]]; 79 } 80 } 81 pii get(int k){ 82 if (S[k].empty())return make_pair(-oo,0); 83 return (*--S[k].end()); 84 } 85 pii calc(int k){ 86 int pos=query_first(1,1,n,dfn[k],dfn[leaf[k]]); 87 if (!pos)pos=dfn[leaf[k]]+1; 88 return query_max(0,1,1,n,dfn[k],pos-1); 89 } 90 void add_val(int k){ 91 while (k){ 92 update_val(0,1,1,n,dfn[k],get(k)); 93 pii o=calc(top[k]); 94 if (fa[top[k]])S[fa[top[k]]].insert(o); 95 k=fa[top[k]]; 96 } 97 } 98 void del_val(int k){ 99 while (k){ 100 pii o=calc(top[k]); 101 if (fa[top[k]])S[fa[top[k]]].erase(S[fa[top[k]]].find(o)); 102 update_val(0,1,1,n,dfn[k],make_pair(-oo,0)); 103 k=fa[top[k]]; 104 } 105 } 106 int get(int p,int x){ 107 if (s[p][x].empty())return -oo; 108 return (*--s[p][x].end()); 109 } 110 void add(int p,int x,int y){ 111 if (!p)del_val(x); 112 s[p][x].insert(y); 113 if (p)update_val(1,1,1,n,dfn[x],make_pair(get(p,x),x)); 114 else{ 115 S[x].insert(make_pair(y,x)); 116 add_val(x); 117 } 118 } 119 void choose(int p,int x){ 120 if (!p)del_val(x); 121 int y=get(p,x); 122 ans+=y; 123 s[p][x].erase(s[p][x].find(y)); 124 if (p)update_val(1,1,1,n,dfn[x],make_pair(get(p,x),x)); 125 else S[x].erase(S[x].find(make_pair(y,x))); 126 add(p^1,x,-y); 127 if (!p)update_Delta(x,-1); 128 else{ 129 del_val(x); 130 update_Delta(x,1); 131 add_val(x); 132 } 133 if (!p)add_val(x); 134 } 135 void Add0(int x,int y){ 136 add(0,x,y); 137 if (get(0,x)!=y)return; 138 choose(0,x); 139 while (x){ 140 int pos=query_last(1,1,n,dfn[top[x]],dfn[x]); 141 if (pos){ 142 pos=idfn[pos]; 143 choose(1,query_max(1,1,1,n,dfn[pos],dfn[pos]+sz[pos]-1).second); 144 return; 145 } 146 x=fa[top[x]]; 147 } 148 } 149 void Add1(int x,int y){ 150 add(1,x,y); 151 if (get(1,x)!=y)return; 152 choose(1,x); 153 choose(0,calc(1).second); 154 } 155 void add_edge(int x,int y,int z){ 156 edge[E].nex=head[x]; 157 edge[E].to=y; 158 edge[E].len=z; 159 head[x]=E++; 160 } 161 void dfs1(int k,int f,int sh){ 162 fa[k]=f; 163 sz[k]=1; 164 dep[k]=sh; 165 for(int i=head[k];i!=-1;i=edge[i].nex) 166 if (edge[i].to!=f){ 167 dfs1(edge[i].to,k,sh+edge[i].len); 168 sz[k]+=sz[edge[i].to]; 169 if (sz[mx[k]]<sz[edge[i].to])mx[k]=edge[i].to; 170 } 171 } 172 void dfs2(int k,int fa,int t){ 173 dfn[k]=++dfn[0]; 174 idfn[dfn[0]]=k; 175 top[k]=t; 176 if (!mx[k])leaf[k]=k; 177 else{ 178 dfs2(mx[k],k,t); 179 leaf[k]=leaf[mx[k]]; 180 } 181 for(int i=head[k];i!=-1;i=edge[i].nex) 182 if ((edge[i].to!=fa)&&(edge[i].to!=mx[k]))dfs2(edge[i].to,k,edge[i].to); 183 } 184 int main(){ 185 scanf("%d%d",&n,&m); 186 memset(head,-1,sizeof(head)); 187 for(int i=1;i<n;i++){ 188 scanf("%d%d%d",&x,&y,&z); 189 add_edge(x,y,z); 190 add_edge(y,x,z); 191 } 192 dfs1(1,0,0); 193 dfs2(1,0,1); 194 build(1,1,n); 195 for(int i=2;i<=n;i++) 196 if (top[i]==i)S[fa[i]].insert(make_pair(-oo,0)); 197 for(int i=1;i<=m;i++){ 198 scanf("%d%d%d",&p,&x,&y); 199 if (p==1){ 200 y-=dep[x]; 201 Add0(x,y); 202 } 203 if (p==2){ 204 y+=dep[x]; 205 Add1(x,y); 206 } 207 printf("%lld\n",ans); 208 } 209 }