这篇还发了洛谷题解

[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 [ZJOI2018]历史 LCT+树形DP

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

  3. 【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)

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

  4. [ZJOI2018]历史

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

  5. 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)

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

  6. BZOJ5212 ZJOI2018历史(LCT)

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

  7. 【BZOJ5212】[ZJOI2018] 历史(LCT大黑题)

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

  8. LOJ2434. 「ZJOI2018」历史 [LCT]

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

  9. bzoj 5212: [Zjoi2018]历史

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

随机推荐

  1. Access restriction required library rt.jar

    在JAVA项目开发中,使用到了BASE64Decoder,但编辑运行时却会出现以下错误:Access restriction required library rt.jar,这里就详细的说明一下如何解 ...

  2. nginx关闭php报错页面显示

    默认情况下nginx是会显示php的报错的,如果要关闭报错显示,需要在/usr/local/php7/etc/php-fpm.d/www.conf文件里面设置,貌似默认情况下在php.ini关闭没效果 ...

  3. loj10104 [POI 2008]Blockade

    传送门 分析 我们知道对于一个割点,我们如果去掉它就会使原来的图被分为若干块,则这是我们将所有块包含的点的个数两两相乘即可,而如果不是割点则对于图的连通性没有影响.注意在最后要加上2*(n-1)表示去 ...

  4. hmset()

    以哈希表方式存放数据

  5. LINQ to SQL连接数据库及语句

    http://www.cnblogs.com/fengzheng126/archive/2012/04/20/2460620.html

  6. 关于文本PDG的字体

    作者:马健邮箱:stronghorse_mj@hotmail.com发布:2008.08.03 有不少人在问为什么有些文本PDG在SSREADER里看到的是宋体,在Acobat里看到的是黑体,其实原因 ...

  7. Windows Services windows服务如何删除服务

    如何删除服务 一.为何要删除服务: 1.当服务文件丢失时,在服务里还会显示. 2.现在好多都会有服务,你看那个不顺眼就可以把它干掉.前提是不用的软件. 二.使用: 使用sc.exe 这个是window ...

  8. echarts设置地图大小比例,大小设置

    设置地图大小可通过以下属性设置: geo.aspectScale number [ default: 0.75 ] 这个参数用于 scale 地图的长宽比. 最终的 aspect 的计算方式是:geo ...

  9. 【bzoj1965】: [Ahoi2005]SHUFFLE 洗牌 数论-快速幂-扩展欧几里得

    [bzoj1965]: [Ahoi2005]SHUFFLE 洗牌 观察发现第x张牌 当x<=n/2 x=2x 当x>n/2 x=2x-n-1 好像就是 x=2x mod (n+1)  就好 ...

  10. git 增量打包

    git diff f506693 ccc253c3 --name-only | xargs tar -czvf update.tar.gz