UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】

题目分析:

不难发现可以用动态DP做。

题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大。

我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存;另一部分将代价加在整条链上,用$d$数组保存。

这时候我们可以发现,一条从$u$到$v$的路径的代价相当于是$d[LCA(u,v)]+\sum_{x \in edge(u,v)}g[x]$。

如果是静态的,可以用树形DP解决。

看过《神奇的子图》的同学都知道,叶子结点是从它的儿子中取两个最大的出来,所以堆维护。

考虑合并。

链从左延申出的最大的$g$的总和记录。链从右延申包括$d$的总和记录,每次向上$update$的时候拼起来与原答案比较即可。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3
  4 typedef long long ll;
  5
  6 const int maxn = 102000;
  7
  8 int n,m;
  9
 10 vector <int> g[maxn];
 11 int sz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn],ind[maxn],dr[maxn];
 12 int tail[maxn],num;
 13
 14 struct Query{int from,to,w;}Q[maxn];
 15 struct Priority_Queue{
 16     priority_queue<ll,vector<ll>,less<ll> > pq,del;
 17     void push(ll now){pq.push(now);}
 18     void pop(){
 19     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
 20     pq.pop();
 21     }
 22     ll top(){
 23     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
 24     if(pq.empty()) return 0;
 25     else return pq.top();
 26     }
 27     ll sec(){
 28     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
 29     if(pq.size() ==0) return 0;
 30     ll oop = pq.top(); pq.pop();
 31     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
 32     if(pq.size() == 0){pq.push(oop);return 0;}
 33     else {ll ret = pq.top();pq.push(oop);return ret;}
 34     }
 35     void Erase(ll now){del.push(now);}
 36 }Son[maxn],Ans;
 37
 38 struct segmentTree{
 39     ll tg,ff,lazy,REC,L,R;
 40 }T[maxn<<2];
 41
 42 void push_down(int now){
 43     T[now<<1].ff += T[now].lazy; T[now<<1|1].ff += T[now].lazy;
 44     T[now<<1].REC += T[now].lazy; T[now<<1|1].REC += T[now].lazy;
 45     T[now<<1].lazy += T[now].lazy; T[now<<1|1].lazy += T[now].lazy;
 46     T[now<<1].R += T[now].lazy; T[now<<1|1].R += T[now].lazy;
 47     T[now].lazy = 0;
 48 }
 49
 50 segmentTree merge(segmentTree alpha,segmentTree beta){
 51     segmentTree RES;RES.lazy = 0;  RES.ff = 0;
 52     RES.tg = alpha.tg + beta.tg;
 53     RES.REC = max(alpha.REC,beta.REC);
 54     RES.REC = max(RES.REC,alpha.R + beta.L);
 55     RES.L = max(alpha.L,alpha.tg + beta.L);
 56     RES.R = max(beta.R,alpha.R + beta.tg);
 57     return RES;
 58 }
 59
 60 void dfs1(int now,int f,int dp){
 61     dep[now] = dp; fa[now] = f;
 62     int maxx = 0;
 63     for(auto it:g[now]){
 64     if(it == f) continue;
 65     dfs1(it,now,dp+1);
 66     sz[now] += sz[it];
 67     if(maxx == 0 || sz[it] > sz[maxx]) maxx = it;
 68     }
 69     son[now] = maxx; sz[now]++;
 70 }
 71
 72 void dfs2(int now,int tp){
 73     top[now] = tp; ind[now] = ++num; dr[num] = now;
 74     if(now == tp) Ans.push(0);
 75     if(son[now]) dfs2(son[now],tp);
 76     else tail[tp] = now;
 77     for(auto it : g[now]){
 78     if(it == fa[now] || it == son[now]) continue;
 79     dfs2(it,it);
 80     }
 81 }
 82
 83 void read(){
 84     scanf("%d%d",&n,&m);
 85     for(int i=1;i<n;i++){
 86     int u,v; scanf("%d%d",&u,&v);
 87     g[u].push_back(v); g[v].push_back(u);
 88     }
 89 }
 90
 91 int QueryLca(int u,int v){
 92     while(top[u] != top[v]){
 93     if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
 94     else v = fa[top[v]];
 95     }
 96     if(dep[u] < dep[v]) return u; else return v;
 97 }
 98
 99 segmentTree Querylen(int now,int tl,int tr,int l,int r){
100     if(tl >= l && tr <= r) return T[now];
101     if(T[now].lazy) push_down(now);
102     int mid = (tl+tr)/2;
103     if(mid < l) return Querylen(now<<1|1,mid+1,tr,l,r);
104     if(mid >= r) return Querylen(now<<1,tl,mid,l,r);
105     segmentTree pp = Querylen(now<<1|1,mid+1,tr,l,r);
106     segmentTree qq = Querylen(now<<1,tl,mid,l,r);
107     return merge(qq,pp);
108 }
109
110 void AddG(int now,int tl,int tr,int place,int w){
111     if(tl == tr){T[now].tg += w;T[now].L += w;return;}
112     if(T[now].lazy) push_down(now);
113     int mid = (tl+tr)/2;
114     if(mid >= place) AddG(now<<1,tl,mid,place,w);
115     else AddG(now<<1|1,mid+1,tr,place,w);
116     T[now] = merge(T[now<<1],T[now<<1|1]);
117 }
118
119 void ModifyG(int now,int tl,int tr,int place){
120     if(tl == tr){
121     tl = dr[tl]; T[now].L = Son[tl].top() + T[now].tg;
122     T[now].REC = T[now].ff + Son[tl].top() + Son[tl].sec();
123     T[now].R = T[now].ff + Son[tl].top();
124     return;
125     }
126     if(T[now].lazy) push_down(now);
127     int mid = (tl+tr)/2;
128     if(mid >= place) ModifyG(now<<1,tl,mid,place);
129     else ModifyG(now<<1|1,mid+1,tr,place);
130     T[now] = merge(T[now<<1],T[now<<1|1]);
131 }
132
133 void ModifyF(int now,int tl,int tr,int l,int r,int w){
134     if(tl >= l && tr <= r){
135     T[now].lazy += w; T[now].ff += w; T[now].R += w; T[now].REC+=w;
136     return;
137     }
138     if(T[now].lazy) push_down(now);
139     int mid = (tl+tr)/2;
140     if(mid >= l) ModifyF(now<<1,tl,mid,l,r,w);
141     if(mid+1 <= r) ModifyF(now<<1|1,mid+1,tr,l,r,w);
142     T[now] = merge(T[now<<1],T[now<<1|1]);
143 }
144
145 void SingleModify(int now,int w){
146     int hole = tail[top[now]];
147     segmentTree fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
148     AddG(1,1,n,ind[now],w); now=fa[top[now]];
149     while(now){
150     segmentTree rl = Querylen(1,1,n,ind[top[hole]],ind[hole]);
151     Ans.Erase(fk.REC); Ans.push(rl.REC);
152     Son[now].Erase(fk.L); Son[now].push(rl.L);
153     hole = tail[top[now]]; fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
154     ModifyG(1,1,n,ind[now]); now = fa[top[now]];
155     }
156     Ans.Erase(fk.REC);
157     fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
158     Ans.push(fk.REC);
159 }
160
161 void WideModify(int now,int LCA,int w){
162     while(dep[now] >= dep[LCA]){
163     segmentTree fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]);
164     if(dep[top[now]] < dep[LCA]) ModifyF(1,1,n,ind[LCA],ind[now],w);
165     else ModifyF(1,1,n,ind[top[now]],ind[now],w);
166     Ans.Erase(fk.REC);
167     fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]);
168     Ans.push(fk.REC);
169     now = fa[top[now]];
170     }
171 }
172
173 void Modify(int u,int v,int w){
174     int LCA = QueryLca(u,v);
175     SingleModify(LCA,w);
176     WideModify(u,LCA,w); // u
177     WideModify(v,LCA,w); // v
178     WideModify(LCA,LCA,-w); // LCA
179 }
180
181 void build_tree(int now,int tl,int tr){
182     if(tl == tr){
183     tl = dr[tl];
184     for(auto it : g[tl]){
185         if(it == son[tl] || it == fa[tl]) continue;
186         Son[tl].push(0);
187     }
188     }else{
189     int mid = (tl+tr)/2;
190     build_tree(now<<1,tl,mid); build_tree(now<<1|1,mid+1,tr);
191     }
192 }
193
194 void work(){
195     dfs1(1,0,1);
196     dfs2(1,1);
197     build_tree(1,1,n);
198     for(int i=1;i<=m;i++){
199     char ch = getchar(); while(ch != ‘+‘ && ch != ‘-‘) ch = getchar();
200     int fr,t,w;
201     if(ch == ‘+‘){
202         scanf("%d%d%d",&fr,&t,&w);Q[i].from=fr;Q[i].to=t;Q[i].w=w;
203     }else{
204         int x; scanf("%d",&x);fr = Q[x].from,t = Q[x].to,w = -Q[x].w;
205     }
206     Modify(fr,t,w);
207     printf("%lld\n",Ans.top());
208     }
209 }
210
211 int main(){
212     read();
213     work();
214     return 0;
215 }

原文地址:https://www.cnblogs.com/Menhera/p/9347536.html

时间: 2024-10-09 04:32:35

UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】的相关文章

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

Tsinsen A1517. 动态树 树链剖分,线段树,子树操作

题目 : http://www.tsinsen.com/A1517 A1517. 动态树 时间限制:3.0s   内存限制:1.0GB 总提交次数:227   AC次数:67   平均分:49.52 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 中国国家队清华集训 2013-2014 第四天 问题描述 小明在楼下种了一棵动态树, 该树每天会在某些节点上长出一些果子. 这棵树的根节点为1, 它有n个节点, n-1条边. 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求

【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝

[bzoj4712] 洪水 [树链剖分+线段树+dp]

题面 传送门 思路 DP方程 首先,这题如果没有修改操作就是sb题,dp方程如下 $dp[u]=max(v[u],max(dp[v]))$,其中$v$是$u$的儿子 我们令$g[u]=max(dp[v])$ 修改? 我们发现,本题中所有的修改都是非负的 也就是说,每一次修改结束以后,$dp[u]$的值只增不减 同时,修改$u$位置的$v[u]$值,只会影响到$u$到根的这一条链上的$dp$值 我们考虑修改后,这条链上的每个点的$dp[u]$值的增量,令这个增量为$delta[u]$ 那么显然当$

【弱校胡策】2016.4.14 (bzoj2164)最短路+状压DP+矩阵乘法+高斯消元+树链剖分+线段树+背包DP

cyyz&qhyz&lwyz&gryz弱校胡策 命题人:cyyz ws_fqk T3暴力写挫了 50+10+0滚粗辣! 奇妙的约会(appointment.cpp/c/pas) [问题描述] DQS和sxb在网上结识后成为了非常好的朋友,并且都有着惊人 的OI水平.在NOI2333的比赛中,两人均拿到了金牌,并保送进入 HU/PKU.于是两人决定在这喜大普奔的时刻进行面基. NOI2333参赛选手众多,所以安排了n个考点,DQS在1号考点, 而sxb在n号考点.由于是举办全国性赛事

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

hdoj 4901 The Romantic Hero DP hdoj 4902 Nice boat 线段树

惨遭丽洁乱虐..这一场也是比得乱七八糟的,4902本是丽洁定义比较难的题,结果数据随机的,被许多暴力水过了..4905考察的是四边形不等式优化,但是这道题的dp方程实际上不满足该优化的条件..朴素的o(n^3)会超时,所以这题目前是没有正解了..我还写了个这题的贪心,强度挺高,可以对大概一半数据,错的误差也只有个位数,还揪出官方第五个数据..朴素dp和贪心跑这个数据都比官方数据多了1,也就证明这题不满足四边形不等式优化的条件.. http://acm.hdu.edu.cn/showproblem