[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)$,可以通过

  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 } 
View Code

 

posted @ 2021-06-08 15:47  PYWBKTDA  阅读(254)  评论(0编辑  收藏  举报