【清华集训2016】数据交互



比较神的\(DDP\)。

首先对于给出的一条链我们分两部分统计:\(lca\)以及其他部分。

我们设两个变量\(w_i,g_i\)。一条路径的权值就是路径上所有点的\(w\)之和\(+g_{lca}\)。所以我们将修改\(w_{lca}\)的权值,修改其他点的\(g\)值。删除的时候就加一条相同的,权值相反的路径。

具体细节就有多了。

首先我们给每个点\(v\)开一个可删除堆表示\(v\)的虚子树中到\(v\)的最长链。再开一个全局的可删除堆记录每条链贡献的答案。我们发现,一条路径可以看成是重链上的\(u,v\)两点(其中\(u\)是\(lca\)),以及这两点分别向虚子树伸出去的一条最长链(可以为空)。它的权值为这条链的\(g\)之和再加上\(w_u\)。当\(u\)等于\(v\)的时候,我们需要找最长链和次长链。

我们发现这就是一个最大连续子段和。

对于线段树上的一个节点,我们记录:

\(mx\)表示答案。

\(lmx\)表示从最左边代表的节点(深度最小)开始的最长链。

\(rmx\)表示从最右边代表的节点(深度最大)开始的最长链。

还要记录\(sum\)表示区间内所有节点的\(w\)只和。

一条重链的链顶的最长链就是这条重链对应的\(lmx\)。

修改的时候暴力将\(lca\)以上\(log\)条重链原来对其父亲贡献的最长链删除掉。更新过后将新的最长链贡献上去。

更多细节就看代码吧:

#include<bits/stdc++.h>
#define ll long long
#define N 100005using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}int n,m;
struct road {int to,next;}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}int fa[N],dep[N];
int size[N],son[N];void dfs(int v) {size[v]=1;for(int i=h[v];i;i=s[i].next) {int to=s[i].to;if(to==fa[v]) continue ;dep[to]=dep[v]+1;fa[to]=v;dfs(to);if(size[son[v]]<size[to]) son[v]=to;size[v]+=size[to];}
}int dfn[N],bot[N],top[N],id;
int lst[N];
void dfs2(int v,int tp) {dfn[v]=++id;lst[id]=v;top[v]=tp;bot[v]=v;if(son[v]) {dfs2(son[v],tp);bot[v]=bot[son[v]];}for(int i=h[v];i;i=s[i].next) {int to=s[i].to;if(to==fa[v]||to==son[v]) continue ;dfs2(to,to);}
}struct tree {int l,r;ll lmx,rmx;ll mx,tag;ll sum;tree() {l=r=lmx=rmx=mx=tag=sum=0;}
}tr[N<<2];struct Heap {priority_queue<ll>add,del;void Pop() {while(del.size()&&add.top()==del.top()) {add.pop();del.pop();}}void Push(ll x) {Pop();add.push(x);}void Del(ll x) {del.push(x);}ll Top() {Pop();return add.top();}ll Sec() {ll x=Top();Del(x);ll y=Top();Push(x);return y;}
}Ans,F[N];tree operator +(const tree &a,const tree &b) {tree tem;tem.l=a.l,tem.r=b.r;tem.mx=max(a.rmx+b.lmx,max(a.mx,b.mx));tem.lmx=max(a.lmx,a.sum+b.lmx);tem.rmx=max(b.rmx,a.rmx+b.sum);tem.sum=a.sum+b.sum;return tem;
}// sum 单点
//tag 链
void Update(int v,int p) {int u=lst[p];ll fir=F[u].Top(),sec=F[u].Sec();tr[v].lmx=tr[v].sum+fir;tr[v].rmx=tr[v].tag+tr[v].sum+fir;tr[v].mx=tr[v].tag+tr[v].sum+fir+sec;
}void build(int v,int l,int r) {tr[v].l=l,tr[v].r=r;if(l==r) {Update(v,l);return ;}int mid=l+r>>1;build(v<<1,l,mid),build(v<<1|1,mid+1,r);tr[v]=tr[v<<1]+tr[v<<1|1];
}void Set(int v,ll f) {tr[v].mx+=f;tr[v].tag+=f;
//  tr[v].lmx+=f;tr[v].rmx+=f;
}void down(int v) {if(tr[v].tag) {Set(v<<1,tr[v].tag),Set(v<<1|1,tr[v].tag);tr[v].tag=0;}
}void add_mx(int v,int l,int r,ll f) {//修改给出的整条链 if(tr[v].l>r||tr[v].r<l) return ;if(l<=tr[v].l&&tr[v].r<=r) {Set(v,f);return ;}down(v);add_mx(v<<1,l,r,f),add_mx(v<<1|1,l,r,f);tr[v]=tr[v<<1]+tr[v<<1|1];
}void add_sum(int v,int p,int f) {//修改lca if(tr[v].l>p||tr[v].r<p) return ;tr[v].sum+=f;if(tr[v].l==tr[v].r) {tr[v].lmx+=f;tr[v].rmx+=f;tr[v].mx+=f;return ;}down(v);add_sum(v<<1,p,f),add_sum(v<<1|1,p,f);tr[v]=tr[v<<1]+tr[v<<1|1];
}void update(int v,int p) {if(tr[v].l>p||tr[v].r<p) return ;if(tr[v].l==tr[v].r) {Update(v,p);return ;}down(v);update(v<<1,p),update(v<<1|1,p);tr[v]=tr[v<<1]+tr[v<<1|1];
}tree query(int v,int l,int r) {if(l<=tr[v].l&&tr[v].r<=r) return tr[v];down(v);int mid=tr[v].l+tr[v].r>>1;if(r<=mid) return query(v<<1,l,r);else if(l>mid) return query(v<<1|1,l,r);else return query(v<<1,l,r)+query(v<<1|1,l,r);
}int lca(int a,int b) {while(top[a]!=top[b]) {if(dep[top[a]]<dep[top[b]]) swap(a,b);a=fa[top[a]];}return dep[a]<dep[b]?a:b;
}void Modify_chain(int a,int b,int f) {while(top[a]!=top[b]) {if(dep[top[a]]<dep[top[b]]) swap(a,b);add_mx(1,dfn[top[a]],dfn[a],f);a=fa[top[a]];}if(dep[a]>dep[b]) swap(a,b);add_mx(1,dfn[a],dfn[b],f);
}void Del(int a,int b) {static tree tem;while(top[a]!=top[b]) {if(dep[top[a]]<dep[top[b]]) swap(a,b);tem=query(1,dfn[top[a]],dfn[bot[a]]);Ans.Del(tem.mx);a=fa[top[a]];}tem=query(1,dfn[top[a]],dfn[bot[a]]);Ans.Del(tem.mx);
}void ADD(int a,int b) {static tree tem;while(top[a]!=top[b]) {if(dep[top[a]]<dep[top[b]]) swap(a,b);tem=query(1,dfn[top[a]],dfn[bot[a]]);Ans.Push(tem.mx);a=fa[top[a]];}tem=query(1,dfn[top[a]],dfn[bot[a]]);Ans.Push(tem.mx);
}void Modify(int a,int b,int w) {int f=lca(a,b);tree tem;for(int i=top[f];i;i=top[fa[i]]) {tem=query(1,dfn[i],dfn[bot[i]]);if(fa[i]) F[fa[i]].Del(tem.lmx);if(i!=top[f]) {Ans.Del(tem.mx);}}Del(a,b);add_sum(1,dfn[f],w);Modify_chain(a,b,w);Modify_chain(f,f,-w);ADD(a,b);for(int i=top[f];i;i=top[fa[i]]) {tem=query(1,dfn[i],dfn[bot[i]]);if(fa[i]) {F[fa[i]].Push(tem.lmx);update(1,dfn[fa[i]]);}if(i!=top[f]) Ans.Push(tem.mx);}
}struct edge {int x,y,w;}e[N];
void out(int v) {int x=top[v];for(int i=dfn[x];;i++) {cout<<lst[i]<<" ";if(i==dfn[v]) return ;}
}int main() {n=Get(),m=Get();int a,b;for(int i=1;i<n;i++) {a=Get(),b=Get();add(a,b),add(b,a);}dfs(1);dfs2(1,1);for(int i=1;i<=n;i++) F[i].Push(0),F[i].Push(0);build(1,1,n);for(int i=1;i<=n;i++) if(i==top[i]) Ans.Push(0);char op;for(int i=1;i<=m;i++) {while(op=getchar(),op!='+'&&op!='-');if(op=='+') {e[i].x=Get(),e[i].y=Get(),e[i].w=Get();Modify(e[i].x,e[i].y,e[i].w);} else {int id=Get();Modify(e[id].x,e[id].y,-e[id].w);}cout<<Ans.Top()<<"\n";}return 0;
}

转载于:https://www.cnblogs.com/hchhch233/p/10566528.html

【清华集训2016】数据交互相关推荐

  1. BZOJ 4732 UOJ #268 [清华集训2016]数据交互 (树链剖分、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4732 (UOJ) http://uoj.ac/problem/268 题解 ...

  2. UOJ #268 BZOJ 4732 [清华集训2016]数据交互 (树链剖分、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4732 (UOJ) http://uoj.ac/problem/268 题解 ...

  3. UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]

    #274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...

  4. [清华集训2016]石家庄的工人阶级队伍比较坚强——三进制FWT

    题目链接: [清华集训2016]石家庄的工人阶级队伍比较坚强 题目大意:有$n=3^m$个人玩石头剪刀布,共$t$轮游戏,每轮每个人要和包括自己的所有人各进行$m$次石头剪刀布.每个人在$m$轮中的决 ...

  5. P6669 [清华集训2016] 组合数问题

    P6669 [清华集训2016] 组合数问题 题意: 给你n,m,k,问有多少对(i,j)满足K∣CijK|C_{i}^{j}K∣Cij​ (Cij是k的倍数C_{i}^{j}是k的倍数Cij​是k的 ...

  6. [清华集训2016]你的生命已如风中残烛——组合数学

    题目链接: [清华集训2016]你的生命已如风中残烛 题目大意:共有$m+1$张牌,其中有$n$张特殊牌,每张特殊牌有一个权值$w_{i}$表示取到这张牌能获得$w_{i}$次再抽牌的机会,保证$\s ...

  7. uoj#268. 【清华集训2016】数据交互(动态dp+堆)

    传送门 动态dp我好像还真没咋做过--通过一个上午的努力光荣的获得了所有AC的人里面的倒数rk3 首先有一个我一点也不觉得显然的定理,如果两条路径相交,那么一定有一条路径的\(LCA\)在另一条路径上 ...

  8. BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)

    BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...

  9. UOJ#274. 【清华集训2016】温暖会指引我们前行

    寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 "冻死宝宝了!" 这时 远处的天边出现了一位火焰之神 "我将赐予你们温暖和希望! ...

最新文章

  1. java object finalize_Java Object finalize() 方法
  2. 树莓派安装python2idle_树莓派开发日记2——Linux!python!GPIO!
  3. 基于现代神经网络通用人工智能架构设计
  4. 【原】移动web动画设计的一点心得——css3实现跑步
  5. 在Python Shell中输入print 'hello'总是报语法错误
  6. CALayer与UIView区别和联系【转】
  7. java 图像渲染_对具有大量图像的视图执行本机渲染性能
  8. androidpn的学习研究(三)androidpn-server服务端几个类说明
  9. python提前退出内层循环,python with提前退出遇到的坑与解决方案
  10. oracle 字符串等于,ORACLE in (字符串,字符串,字符串)
  11. 图(3)——邻接链表法
  12. IEEE期刊最新的影响因子
  13. 【调剂】长江大学张菲菲教授招收硕士生
  14. 教授专栏14 | 陈泰元: 提升公司治理之路--高管薪酬追回条款
  15. Python学习必看书籍_带你高效学习
  16. Redis过期策略---实现原理
  17. 卸载Autodesk系列之后电脑屏幕灰白怎么解决
  18. 机器学习之随机森林填补缺失值和众数填补缺失值
  19. linux远程文件拷贝方式,linux远程拷贝文件
  20. 矮油~ 二叉树的深度优先遍历与广度优先遍历 [ C++ 实现 ]

热门文章

  1. [python数据分析] 简述幂率定律及绘制Power-law函数
  2. linux kvm百度云,如何在 Ubuntu Linux 上使用 KVM 云镜像
  3. 科学家解码脑信号以控制机器人假肢
  4. 通过细胞自动机,AI在「我的世界」学会了盖房子
  5. 数学好=编程能力强?MIT新发现:二者激活大脑区域并不同
  6. RTX 3090 AI性能实测:FP32训练速度提升50%,张量核心缩水
  7. 专访阿里达摩院聂再清:不能让每个人无差别享受AI,是程序员的耻辱
  8. 一路撑起支付宝的OceanBase数据库,背后究竟有哪些杀手锏?| 云·创课程报名
  9. 被乐高AI“照妖镜”一照,发现你的本体原来是人偶
  10. 禾多推出高精度定位和自动驾驶验证平台!倪凯:助力行业量产,定位中国向导...