[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 ...
随机推荐
- 梦幻西游H5游戏超详细图文架设教程
前言 想体验经典Q版西游霸服快乐吗?想体验满级VIP的尊贵吗?想体验一招秒杀的爽快吗?各种极品装备.翅膀.宠物通通给你,就在梦幻西游! 本文讲解梦幻西游H5游戏的架设教程,想研究H5游戏如何实现,体验 ...
- 微信小程序应用安全分析及设计
针对微信关于小程序安全设计的分析 针对微信小程序开发配置及部分配置机制分析微信小程序安全设计: AppSecret 管理员生成AppSecret,在与微信后台交互过程中部分接口使用,如 auth.co ...
- 从零入门 Serverless | 在线应用的 Serverless 实践
作者 | 唐慧芬(黛忻) 阿里云产品专家 导读:毫无疑问,Serverless 能够在效率和成本上给用户带来巨大收益.那具体到落地又应该怎么做呢?本文就给大家详细解读 Serverless 的落地实践 ...
- 基于Hyperledger Fabric实现ERC721
介绍 超级账本(Hyperledger)项目是首个面向企业应用场景的开源分布式账本平台.由linux基金会牵头,包括 IBM 等 30家初始企业成员共同成立的. 区块链网络主要有三种类型:公共区块链. ...
- 3 Implementation: The Big Picture 实现:蓝图
三.Implementation: The Big Picture 实现:蓝图 3.1 Layering of a .NET Solution .Net解决方案的分层 The picture belo ...
- 【c++ Prime 学习笔记】第1章 开始
1.1 编写一个简单的程序 int main() { return 0; } 函数 包含4部分: 返回类型(return type) 函数名(function name) 形参列表(parameter ...
- Sequence Model-week1编程题3-用LSTM网络生成爵士乐
Improvise a Jazz Solo with an LSTM Network 实现使用LSTM生成音乐的模型,你可以在结束时听你自己的音乐,接下来你将会学习到: 使用LSTM生成音乐 使用深度 ...
- ffmpeg剪视频
ffmpeg裁剪合并视频 ffmpeg提供简单的命令参数: ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTP ...
- hystrix的配置说明
在我们的日常开发中,有些时候需要和第三方系统进行对接操作,或者调用其他系统的 api 接口,但是我们不能保证这些第三方系统的接口一定是稳定的,当系统中产生大量的流量来访问这些第三方接口,这些第三方系统 ...
- xmake v2.5.9 发布,改进 C++20 模块,并支持 Nim, Keil MDK 和 Unity Build
xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能 ...