记$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 }

[loj574]黄金矿工的更多相关文章

  1. [Tyvj Aug11] 黄金矿工

    传送门 Description 黄金矿工是一个经典的小游戏,它可以锻炼人的反应能力.该游戏中,可以通过“挖矿”获得积分并不断升级.玩家可以在线玩flash版黄金矿工,也可以下载后玩单机版黄金矿工.目前 ...

  2. 洛谷3961 [TJOI2013]黄金矿工

    题目描述 小A最近迷上了在上课时玩<黄金矿工>这款游戏.为了避免被老师发现,他必须小心翼翼,因此他总是输.在输掉自己所有的金币后,他向你求助.每个黄金可以看做一个点(没有体积).现在给出你 ...

  3. LeetCode 5215. 黄金矿工(Java)DFS

    题目: 5215. 黄金矿工 你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注.每个单元格中的整数就表示这一单元格中的黄金数量:如果该 ...

  4. 黄金矿工(LeetCode Medium难度)1129题 题解(DFS)

    题目描述: 给定一个二维网络,给定任意起点与终点.每一步可以往4个方向走.要找出黄金最多的一条线路. 很明显的是要“一条路走到黑,一直下去直到某个条件停止”. 运用dfs(深度优先搜索)求解. 因为起 ...

  5. 洛咕 P3961 [TJOI2013]黄金矿工

    甚至都不是树形背包= = 把每条线抠出来,这一条线就是个链的依赖关系,随便背包一下 // luogu-judger-enable-o2 #include<bits/stdc++.h> #d ...

  6. leetcode-157周赛-5215黄金矿工

    题目描述: 方法一:dfs class Solution: def getMaximumGold(self, grid: List[List[int]]) -> int: maxx = 0 R, ...

  7. 收藏的几个经典Flash

    本人收藏了几个有意思的Flash,在此与大家分享下 1.黄金矿工中文版.swf 2.中国象棋.swf 3.运动的老鼠.swf 4.时钟.swf 5. 2048.swf 6.小猫逃跑.swf

  8. HDU 4341 分组背包

    B - Gold miner Time Limit:2000MS      Memory Limit:32768KB     Description Homelesser likes playing ...

  9. 一 手游开发工具cocos2d-x editor初识

    可学习的demo: 7个实战项目 flappybird(飞扬小鸟).popstar(消灭星星).fruitninja(水果忍者).2048(数度消除). moonwarriors(月亮战神).frui ...

随机推荐

  1. T-SQL——函数——字符串操作函数

    目录 0. 加号(+) 1. LEFT和RIGHT 2. SUBSTRING 3. LEN和DATALENGTH 4. CHARINDEX和PATINDEX 5. REPLACE 6. REPLICA ...

  2. Spring配置文件结构对于生成Bean的影响

    Spring配置文件结构对于生成Bean的影响 有段时间忙于毕设,导致Spring学习的东西忘了很多,所以最近又开始从头看Spring的基础.基础的Bean的装配不再多说了.这一次,主要是深入一点了解 ...

  3. 面试官:为什么需要Java内存模型?

    面试官:今天想跟你聊聊Java内存模型,这块你了解过吗? 候选者:嗯,我简单说下我的理解吧.那我就从为什么要有Java内存模型开始讲起吧 面试官:开始你的表演吧. 候选者:那我先说下背景吧 候选者:1 ...

  4. Go语言核心36讲(Go语言基础知识四)--学习笔记

    04 | 程序实体的那些事儿(上) 还记得吗?Go 语言中的程序实体包括变量.常量.函数.结构体和接口. Go 语言是静态类型的编程语言,所以我们在声明变量或常量的时候,都需要指定它们的类型,或者给予 ...

  5. 前段之BOM ----DOM

    一.介绍 BOM(Browser Object Model)是指浏览器对象模型,它使 JavaScript 有能力与浏览器进行"对话". DOM (Document Object ...

  6. 洛谷4299首都(LCT维护动态重心+子树信息)

    这个题目很有意思 QWQ 根据题目描述,我们可以知道,首都就是所谓的树的重心,那么我们假设每颗树的重心都是\(root\)的话,对于每次询问,我们只需要\(findroot(x)\)就可以. 那么如何 ...

  7. Spring Boot 整合 Apache Ignite

    关于Ignite的介绍,这边推荐三个链接进行学习了解. https://ignite.apache.org/,首选还是官网,不过是英文版,如果阅读比较吃力可以选择下方两个链接. https://www ...

  8. 在kivy中加图片

    from kivy.app import App from kivy.uix.scatterlayout import ScatterLayout from kivy.uix.image import ...

  9. Java:AQS 小记-1(概述)

    Java:AQS 小记-1(概述) 概述 全称是 Abstract Queued Synchronizer(抽象队列同步器),是阻塞式锁和相关的同步器工具的框架,这个类在 java.util.conc ...

  10. Linux中检查字符串是否为合法IP地址的shell脚本

    #!/bin/bash #判断IP地址是否为有效IP CHKECK_IP () { CHECK_STEP1=`echo $1 | awk -F"." '{print NF}'` i ...