[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 }
[loj574]黄金矿工的更多相关文章
- [Tyvj Aug11] 黄金矿工
传送门 Description 黄金矿工是一个经典的小游戏,它可以锻炼人的反应能力.该游戏中,可以通过“挖矿”获得积分并不断升级.玩家可以在线玩flash版黄金矿工,也可以下载后玩单机版黄金矿工.目前 ...
- 洛谷3961 [TJOI2013]黄金矿工
题目描述 小A最近迷上了在上课时玩<黄金矿工>这款游戏.为了避免被老师发现,他必须小心翼翼,因此他总是输.在输掉自己所有的金币后,他向你求助.每个黄金可以看做一个点(没有体积).现在给出你 ...
- LeetCode 5215. 黄金矿工(Java)DFS
题目: 5215. 黄金矿工 你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注.每个单元格中的整数就表示这一单元格中的黄金数量:如果该 ...
- 黄金矿工(LeetCode Medium难度)1129题 题解(DFS)
题目描述: 给定一个二维网络,给定任意起点与终点.每一步可以往4个方向走.要找出黄金最多的一条线路. 很明显的是要“一条路走到黑,一直下去直到某个条件停止”. 运用dfs(深度优先搜索)求解. 因为起 ...
- 洛咕 P3961 [TJOI2013]黄金矿工
甚至都不是树形背包= = 把每条线抠出来,这一条线就是个链的依赖关系,随便背包一下 // luogu-judger-enable-o2 #include<bits/stdc++.h> #d ...
- leetcode-157周赛-5215黄金矿工
题目描述: 方法一:dfs class Solution: def getMaximumGold(self, grid: List[List[int]]) -> int: maxx = 0 R, ...
- 收藏的几个经典Flash
本人收藏了几个有意思的Flash,在此与大家分享下 1.黄金矿工中文版.swf 2.中国象棋.swf 3.运动的老鼠.swf 4.时钟.swf 5. 2048.swf 6.小猫逃跑.swf
- HDU 4341 分组背包
B - Gold miner Time Limit:2000MS Memory Limit:32768KB Description Homelesser likes playing ...
- 一 手游开发工具cocos2d-x editor初识
可学习的demo: 7个实战项目 flappybird(飞扬小鸟).popstar(消灭星星).fruitninja(水果忍者).2048(数度消除). moonwarriors(月亮战神).frui ...
随机推荐
- MIPS流水线技术
华中科技大学 - 计算机硬件系统设计 单周期指令运行动态 Instruction Fetch Instruction Decode Execution MEM Write Back 单周期时空图 设耗 ...
- C++ 与 Visual Studio 2019 和 WSL(二)
终端 A more integrated terminal experience | Visual Studio Blog (microsoft.com) Say hello to the new V ...
- 想要彻底搞懂大厂是如何实现Redis高可用的?看这篇文章就够了!(1.2W字,建议收藏)
高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...
- Java:NIO 学习笔记-2
Java:NIO 学习笔记-2 上一篇 NIO 学习笔记-1 看了 尚硅谷 的相应教程,此处又对比看了 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 前言 在 Java 的软件设计开 ...
- DDD领域驱动设计-概述-Ⅰ
如果我看得更远,那是因为我站在巨人的肩膀上.(If I have seen further it is by standing on ye shoulder of Giants.) ...
- OO第四单元作业总结及课程总结
一.本单元作业架构设计 1.第一次作业 本单元首次接触到UML以及相关概念,在面对第一次作业时首先花了很大功夫去阅读官方接口中各种UmlElement的代码,才理解了输入的模型元素中各属性的含义.总的 ...
- 热身训练1 Problem B. Harvest of Apples
http://acm.hdu.edu.cn/showproblem.php?pid=6333 题意: 求 C(0,n)+C(1,n)+...+C(m,n) 分析: 这道题,我们令s(m,n) = C( ...
- GEOS使用记录
由于需要计算GIS障碍物的缓冲区,所以研究了 一下GEOS库的使用,将使用的一些细节内容记录一下: 1.vs2010IDE无法编译较高版本的GEOS库,较高版本的库使用了更加高级的C++语法,如果想使 ...
- Linux入门必须养成的七大习惯
对于很多Linux初学者来说,在刚开始使用linux系统时会感到很多的不适.这里为大家整理了自己以前linux入门时别人告诉我的七个习惯.我相信如果你运用了这七个习惯,在你使用Linux时你会感觉更安 ...
- BF算法和KMP算法
这两天复习数据结构(严蔚敏版),记录第四章串中的两个重要算法,BF算法和KMP算法,博主主要学习Java,所以分析采用Java语言,后面会补上C语言的实现过程. 1.Brute-Force算法(暴力法 ...