[ZJOI2018]历史(LCT)

时间:2022-11-05 12:35:04

这篇还发了洛谷题解

[Luogu4338] [BZOJ5212]

题解

题意

给出一棵树,给定每一个点的 \(access\) 次数,计算轻重链切换次数的最大值,带修改.

先考虑不带修改怎么做

假设 \(u\) 的子树发生了两次 \(access\) , 那么当且仅当这两次 \(access\) 的点来自 \(u\) 的两个不同的儿子的子树 , 答案才会 \(+1\)

要使得答案最大 , 就是尽量让所有相邻发生的 \(access\) 都来自不同子树

把同类型的数挪到一边就是当 \(2\times h\ge t+1\) 时,答案是 \(2(t-h)\) ,否则是 \(t-1\)

考虑待修改怎么做

令$ f_i$表示 \(i\) 的子树 access 的总次数,如果 \(2f_i\ge f_{fa_i}+1\) 那么连实边 \((i,fa_i)\) 其他的都是虚边

如果把\(i\)子树中的点\(j\)权值加上\(w\) , 则只会影响\(j\)到根节点路径的答案和虚实边关系 ,

因为 \(2(f_i+w)\ge(f_{fa_i}+w)+1\)所以实边还是实边 , 并且答案不会变化

所以我们只需要找到路径上的虚边进行(暴力)修改就好了 , 然后 \(ans+=\) 这个点更新后的答案 \(-\)更新前的答案

这题难在构造实儿子(边)和虚儿子(边) , 注意到虚边只有\(log\)条 , 所以如果转化为

只需要修改虚儿子(边)的信息 , 剩下的通过\(splay\)或者其他一些操作完成就接近正解了

本题中有一个贪心 , 就是子树中\(size>=\)自己的一半的点的贡献的重要性 , 这个点再大也无法影响答案了 , 转化为实儿子(边)对当前点的答案无影响 , 其他的就都定义为轻边

修改是就是\(splay+\)暴力中的分类讨论

注意 : 对于\(rs\)变为虚儿子和\(y\)变为实儿子的判断都要考虑清楚

还有一个特别容易忽视的点 : 为了使崛起过程中战争次数最多 , 尽量要让所有相邻发生的\(access\)都来自不同的子树 , 于是统计\(maxp\)必须考虑\(u\)这个点 , 否则只有\(70\)分

可见复杂的题目一定要对每个子问题都分类清楚 , 特别是 端点 , 边界 , 根节点 , 叶节点 这些地方一般都要特判

否则甚至可能做不出,比如[HDU4035]Maze[HDU4089]Activation

难题就是简单题的叠加 , \(ZJOI\)的题真神仙

细节详见代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
} const int MAXN=4e5+5;
const int MAXM=8e5+5; struct Edge{
int v,next;
}e[MAXM];
int first[MAXN],Ecnt=1;
inline void Add_edge(int u,int v){
e[++Ecnt]=(Edge){v,first[u]};
first[u]=Ecnt;
} int n,m;
LL ans; namespace LCT{
LL sum[MAXN],aux[MAXN],val[MAXN];
int ch[MAXN][2],par[MAXN];
#define ls ch[rt][0]
#define rs ch[rt][1]
inline bool chk(int x){return ch[par[x]][1]==x;}
inline bool nrt(int x){return ch[par[x]][0]==x||ch[par[x]][1]==x;}
inline void pushup(int rt){sum[rt]=sum[ls]+sum[rs]+val[rt]+aux[rt];}//全部加起来
inline void rotate(int x){
int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
ch[y][k]=w,par[w]=y;
if(nrt(y)) ch[z][chk(y)]=x; par[x]=z;
ch[x][k^1]=y,par[y]=x;
pushup(y);pushup(x);
}
inline void splay(int x){
while(nrt(x)){
int y=par[x];
if(nrt(y)){
if(chk(x)==chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
}
#undef ls
#undef rs
}using namespace LCT; //如果按常规写法会错[https://www.luogu.org/recordnew/show/17153906]
//为了使崛起过程中战争次数最多,尽量要让所有相邻发生的access都来自不同的子树
//于是统计maxp必须考虑u这个点
/*inline void dfs(int u,int pre){
int maxp=0;
sum[u]=val[u],par[u]=pre;
for(int i=first[u];i;i=e[i].next){
int v=e[i].v;
if(v==pre) continue;
dfs(v,u);
sum[u]+=sum[v];
if(sum[v]>sum[maxp]) maxp=v;
}
ans+=min(sum[u]-1,2*(sum[u]-sum[maxp]));
if(sum[maxp]*2>=sum[u]+1) ch[u][1]=maxp;
aux[u]=sum[u]-val[u]-sum[ch[u][1]];
}*/ inline void dfs(int u,int pre){
LL maxp=val[u];int p=0;
sum[u]=val[u],par[u]=pre;
for(int i=first[u];i;i=e[i].next){
int v=e[i].v;
if(v==pre) continue;
dfs(v,u);
sum[u]+=sum[v];
if(sum[v]>maxp) maxp=sum[p=v];
}
ans+=min(sum[u]-1,2*(sum[u]-maxp));
if(maxp*2>=sum[u]+1) ch[u][1]=p;//存重儿子
aux[u]=sum[u]-val[u]-sum[ch[u][1]];//虚边的size
} #define ls ch[u][0]
#define rs ch[u][1]
inline LL calc(int u,LL total,LL weight){
if(rs) return (total-weight)*2;
else if(val[u]*2>=total+1) return(total-val[u])*2;
else return total-1;
} inline void modify(int u,int w){
splay(u);
LL total=sum[u]-sum[ls],weight=sum[rs];
ans-=calc(u,total,weight);
sum[u]+=w,val[u]+=w,total+=w;
if(weight*2<=total) aux[u]+=weight,rs=0;//变为虚边
ans+=calc(u,total,weight);
pushup(u);
//access
//重点还是维护虚边或虚儿子信息,即access
int v;
for(u=par[v=u];u;u=par[v=u]){
splay(u);
total=sum[u]-sum[ls],weight=sum[rs];
ans-=calc(u,total,weight);
sum[u]+=w,aux[u]+=w,total+=w;//虚边size+=w;
if(weight*2<=total) aux[u]+=weight,rs=0,weight=0;
if(sum[v]*2>=total+1) aux[u]-=sum[v],rs=v,weight=sum[v];
ans+=calc(u,total,weight);
pushup(u);
}
}
#undef ls
#undef rs int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<=n-1;i++){
int x=read(),y=read();
Add_edge(x,y);
Add_edge(y,x);
}
dfs(1,0);
printf("%lld\n",ans);
for(int i=1;i<=m;i++){
int x=read(),y=read();
modify(x,y);
printf("%lld\n",ans);
}
}

[ZJOI2018]历史(LCT)的更多相关文章

  1. Luogu4338 ZJOI2018 历史 LCT、贪心

    传送门 题意:在$N$个点的$LCT$中,最开始每条边的虚实不定,给出每一个点的$access$次数,求一种$access$方案使得每条边的虚实变换次数之和最大,需要支持动态增加某个点的$access ...

  2. P4338 &lbrack;ZJOI2018&rsqb;历史 LCT&plus;树形DP

    \(\color{#0066ff}{ 题目描述 }\) 这个世界有 n 个城市,这 n 个城市被恰好 \(n-1\) 条双向道路联通,即任意两个城市都可以 互相到达.同时城市 1 坐落在世界的中心,占 ...

  3. 【BZOJ5212】&lbrack;ZJOI2018&rsqb;历史(Link-Cut Tree)

    [BZOJ5212][ZJOI2018]历史(Link-Cut Tree) 题面 洛谷 BZOJ 题解 显然实际上就是给定了一棵树和每个点被\(access\)的次数,求解轻重链切换的最大次数. 先考 ...

  4. &lbrack;ZJOI2018&rsqb;历史

    [ZJOI2018]历史 最大化access轻重链的切换次数 考虑一个点的贡献,即它交换重儿子的次数 发现这个次数只和它自己ai以及每个儿子的子树次数和有关. 一个关键的事实是: 我们可以自上而下进行 ...

  5. 洛谷P4338 &lbrack;ZJOI2018&rsqb;历史(LCT,树形DP,树链剖分)

    洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...

  6. BZOJ5212 ZJOI2018历史(LCT)

    首先相当于最大化access的轻重边交换次数. 考虑每个点作为战场(而不是每个点所代表的国家与其他国家交战)对答案的贡献,显然每次产生贡献都是该点的子树内(包括自身)此次access的点与上次acce ...

  7. 【BZOJ5212】&lbrack;ZJOI2018&rsqb; 历史(LCT大黑题)

    点此看题面 大致题意: 给定一棵树每个节点\(Access\)的次数,求最大虚实链切换次数,带修改. 什么是\(Access\)? 推荐你先去学一学\(LCT\)吧. 初始化(不带修改的做法) 首先考 ...

  8. LOJ2434&period; 「ZJOI2018」历史 &lbrack;LCT&rsqb;

    LOJ 思路 第一眼看似乎没有什么思路,试着套个DP上去:设\(dp_x\)表示只考虑\(x\)子树,能得到的最大答案. 合并的时候发现只有\(x\)这个点有可能做出新的贡献,而做出新贡献的时候必然是 ...

  9. bzoj 5212&colon; &lbrack;Zjoi2018&rsqb;历史

    Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有n个城市,这n个城市被恰好n?1条双向道路联通,即任意两个城 ...

随机推荐

  1. SQL server学习

    慕课网sql server学习 数据库第一印象:desktop--web server--database server** 几大数据库:sql server.oracle database.DB2. ...

  2. 项目管理10000 hours – 瞎扯谈系列

    本系列会 zz 网上现有的文章,套句经典的话就是死磕自己,娱乐大众. 项目能否按时完成是项目管理的重要目标,将会面临的问题有团队的稳定性,冲突,会议以及压力. 团队中适度的人员流动是可以理解的,如何减 ...

  3. java中IO流操作的标准异常类

    package 加入异常处理的字节流操作; import java.io.FileNotFoundException; import java.io.FileOutputStream; import ...

  4. spring初始化

    * Created by litao on 15/12/29. */@Component("initTagDataProcessor")public class InitTagDa ...

  5. 为ownCloud配置SSL连接

    为ownCloud配置SSL连接 在你开始使用ownCloud之前,强烈建议你在ownCloud中启用SSL支持.使用SSL可以提供重要的安全好处,比如加密ownCloud流量并提供适当的验证.在本教 ...

  6. C语言之预处理命令

    /**************************************************************************** Title:C之预处理命令 Time:201 ...

  7. Spring、SpringMVC、SpringData &plus; JPA 整合详解

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7759874.html ------------------------------------ ...

  8. C&num; 解决winform 窗体控件在窗体变化时闪烁的问题

    在窗体form代码中加入如下代码即可: protected override CreateParams CreateParams { get { CreateParams cp = base.Crea ...

  9. 洛谷 P2764 解题报告

    P2764 最小路径覆盖问题 问题描述: 给定有向图\(G=(V,E)\).设\(P\) 是\(G\) 的一个简单路(顶点不相交)的集合.如果\(V\) 中每个顶点恰好在\(P\) 的一条路上,则称\ ...

  10. create react app 项目部署在Spring&lpar;Tomcat&rpar;项目中

    网上看了许多,大多数都是nginx做成静态项目,但是这样局限性太多,与Web项目相比许多服务端想做的验证都很麻烦,于是开始了艰难的探索之路,终于在不经意间试出来了,一把辛酸... 正常的打包就不说了. ...