模板:全局平衡二叉树

所谓全局平衡二叉树,就是在全局来看都很平衡的二叉树。

(逃

前言

这个引言倒是实话(雾
可以把一些本来只能用树剖两个 log 做的问题在单log 时间复杂度解决。
修改通常来说只能支持单点修改
查询解决链上问题或者全局问题更为方便(但子树似乎也是可以的)
常数比较大,但总比LCT强

解析

树剖其实可以看成对每一条重链上的节点都维护一棵线段树,同一条重链上的节点享受同样的查询复杂度。
但是我们发现这样“看似平衡”的数据结构其实并不平衡,因为有的节点可能有非常多的轻儿子,而有的节点可能根本没有轻儿子,前者在大部分数据中都会更多的被访问到。
因此引出了全局平衡二叉树的思想。

定义一个节点的权值 valxval_xvalx其所有轻儿子子树大小+1
全局平衡二叉树的结构和LCT十分相似。先对原树进行重链剖分,然后对每个重链维护一棵二叉查找树,这里每次选择的区间断点不是中点(那样就是线段树了),而是按照 valvalval 找到的带权重心,并把二叉查找树根节点的父亲设为原树重链头的父亲。
(于LCT不同的是,这里二叉查找树的结构是静态的。)
本人的写法中二叉搜索树的非叶节点都是虚点。

对于一个单点修改,修改其信息后不断跳父亲更新即可。

对于一个链上查询,对应的是若干条重链的前缀和一条重链的区间,前者由建树的定义不难发现每次消耗复杂度必然siz翻倍,故是 log⁡n\log nlogn 的,后者由于树高为 log,故也是 log⁡n\log nlogn 的。

子树就在子树根节点的二叉查找树上找一找需要的节点信息合并即可。

代码

P4751 【模板】“动态DP”&动态树分治(加强版)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("ok\n")
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}const int N=2e6+100;
const int inf=1e9+100;
const bool Flag=0;int n,m;
int tot;struct matrix{int x,y;int a[3][3];matrix(int X=0,int Y=0,int u=-inf,int v=-inf,int p=-inf,int q=-inf):x(X),y(Y){a[1][1]=u;a[1][2]=v;a[2][1]=p;a[2][2]=q;}
};
matrix operator * (const matrix &u,const matrix &v){matrix res(u.x,v.y);for(int k=1;k<=u.y;k++){for(int i=1;i<=u.x;i++){int tmp=u.a[i][k];for(int j=1;j<=v.y;j++) res.a[i][j]=max(res.a[i][j],tmp+v.a[k][j]);}}return res;
}vector<int>e[N];
int a[N],fa[N],siz[N],val[N],hson[N];
int s0[N],s1[N];
void dfs1(int x,int f){siz[x]=1;fa[x]=f;for(int to:e[x]){if(to==f) continue;dfs1(to,x);siz[x]+=siz[to];if(siz[to]>siz[hson[x]]) hson[x]=to;}val[x]=siz[x]-siz[hson[x]];return;
}
struct node{matrix ans;int fa,ls,rs;
}tr[N];
int nod[N];
inline void pushup(int x){tr[x].ans=tr[tr[x].rs].ans*tr[tr[x].ls].ans;
}
int build(int l,int r,int f){if(l==r){int x=nod[l];matrix o(2,2,s0[x],s1[x],s0[x],-inf);tr[x].ans=o;tr[x].fa=f;return x;}int cur(0),sum(0),now(0);for(int i=l;i<=r;i++) sum+=val[nod[i]];    for(int i=l;i<=r;i++){cur+=val[nod[i]];if(cur*2<sum) continue;if(i==r) --i;now=++tot;tr[now].fa=f;tr[now].ls=build(l,i,now);tr[now].rs=build(i+1,r,now);break;}pushup(now);return now;
}
inline void ins(int rt,int op){int f=tr[rt].fa;if(f){s0[f]+=op*max(tr[rt].ans.a[1][1],max(tr[rt].ans.a[1][2],max(tr[rt].ans.a[2][1],tr[rt].ans.a[2][2])));s1[f]+=op*max(tr[rt].ans.a[1][1],tr[rt].ans.a[2][1]);matrix o(2,2,s0[f],s1[f],s0[f],-inf);tr[f].ans=o;}
}
int dfs2(int x,int f){int top(0);for(int p=x;p;p=hson[p]){for(int to:e[p]){if(to==hson[p]||to==fa[p]) continue;dfs2(to,p);}}for(int p=x;p;p=hson[p]){nod[++top]=p;}int rt=build(1,top,f);if(f) ins(rt,1);return rt;
}
inline void upd(int x,int y){if(!x) return;s1[x]=y;for(int p=x;p;p=tr[p].fa){if(tr[p].fa&&tr[tr[p].fa].ls!=p&&tr[tr[p].fa].rs!=p) ins(p,-1);if(p==x) tr[p].ans.a[1][2]=y;          if(p>n) pushup(p);if(tr[p].fa&&tr[tr[p].fa].ls!=p&&tr[tr[p].fa].rs!=p) ins(p,1),p=tr[p].fa;}return;
}signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();for(int i=1;i<=n;i++) s1[i]=a[i]=read();for(int i=1;i<n;i++){int x=read(),y=read();e[x].push_back(y);e[y].push_back(x);}tot=n;dfs1(1,0);int rt=dfs2(1,0),lst(0);for(int i=1;i<=m;i++){int x=read()^lst,y=read();upd(x,s1[x]+y-a[x]);a[x]=y;printf("%d\n",lst=max(tr[rt].ans.a[1][1],max(tr[rt].ans.a[1][2],max(tr[rt].ans.a[2][1],tr[rt].ans.a[2][2]))));}return 0;
}

practice

SP2666 QTREE4 - Query on a tree IV
本题的难点是如果对每个点开一个堆存储所有轻儿子到父亲的合法点距离最大值,修改时需要对堆操作,复杂度就两个log了。
一个神奇且小清新的优化方法是把整棵树三度化,这样就只有一个轻儿子,不必开堆了。

代码实现参考了 @hehezhou 的博客。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("ok\n")
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}const int N=4e5+100;
const int inf=1e9;
const bool Flag=0;int n,m;#define pr pair<int,int>
#define mkp make_pair
vector<pr>e[N];
int dep[N],tot;
int lson[N],wson[N],siz[N],val[N];
inline void link(int x,int y){//debug("link: %d %d\n",x,y);if(!lson[x]) lson[x]=y;else wson[x]=y;
}
void dfs0(int x,int f){link(x+n,x);for(int i=0;i<(int)e[x].size();i++){if(e[x][i].first==f){e[x].erase(e[x].begin()+i);break;}}for(int i=0;i<(int)e[x].size();i++){dep[e[x][i].first+n]=dep[x];dep[e[x][i].first]=dep[x]+e[x][i].second;dfs0(e[x][i].first,x);}for(int i=1;i<(int)e[x].size();i++) link(e[x][i-1].first+n,e[x][i].first+n);if(!e[x].empty()) link(x,e[x][0].first+n);
}
struct node{int l,r,ls,rs,lmax,rmax,ans,pre,suf,fa;
}tr[N];
void dfs1(int x){siz[x]=1;if(wson[x]){dfs1(wson[x]);siz[x]+=siz[wson[x]];}if(lson[x]){dfs1(lson[x]);siz[x]+=siz[lson[x]];}if(siz[wson[x]]<siz[lson[x]]) swap(lson[x],wson[x]);val[x]=siz[x]-siz[wson[x]];return;
}
int zhan[N];
int build(int l,int r,int f){if(l==r){tr[zhan[l]].pre=tr[zhan[l]].suf=zhan[l];tr[zhan[l]].l=tr[zhan[l]].r=l;tr[zhan[l]].fa=f;return zhan[l];}int sum(0),cur(0),now(0);for(int i=l;i<=r;i++) sum+=val[zhan[i]];for(int i=l;i<=r;i++){cur+=val[zhan[i]];if(cur*2<sum) continue;if(i==r) --i;now=++tot;tr[now].ls=build(l,i,now);tr[now].rs=build(i+1,r,now);break;}tr[now].l=l;tr[now].r=r;tr[now].pre=zhan[l];tr[now].suf=zhan[r];tr[now].fa=f;if(Flag) printf("now=%d (%d %d)\n",now,l,r);return now;
}
int dfs2(int x,int f){int top=0;for(int p=x;p;p=wson[p]) zhan[++top]=p;if(Flag) for(int i=1;i<=top;i++) printf("%d ",zhan[i]);if(Flag) puts("\n");int rt=build(1,top,f);for(int p=x;p;p=wson[p]){if(lson[p]) tr[p].ls=dfs2(lson[p],p);}return rt;
}
bool ban[N];
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
inline void pushup(int x){if(tr[x].l==tr[x].r){int d=tr[ls(x)].lmax+dep[tr[ls(x)].pre]-dep[x];if(!ban[x]){tr[x].lmax=tr[x].rmax=max(d,0);tr[x].ans=max(tr[ls(x)].ans,0);}else{tr[x].lmax=tr[x].rmax=d;tr[x].ans=tr[ls(x)].ans;}return;}else{tr[x].lmax=max(tr[ls(x)].lmax,tr[rs(x)].lmax+(dep[tr[rs(x)].pre]-dep[tr[ls(x)].pre]));tr[x].rmax=max(tr[rs(x)].rmax,tr[ls(x)].rmax+(dep[tr[rs(x)].suf]-dep[tr[ls(x)].suf]));tr[x].ans=max(max(tr[ls(x)].ans,tr[rs(x)].ans),tr[ls(x)].rmax+tr[rs(x)].lmax+dep[tr[rs(x)].pre]-dep[tr[ls(x)].suf]);return;}  
}
void init(int x){if(!x) return;if(tr[x].l==tr[x].r){init(tr[x].ls);}else{init(tr[x].ls);init(tr[x].rs);}pushup(x);if(Flag) printf("x=%d lmax=%d rmax=%d ans=%d\n",x,tr[x].lmax,tr[x].rmax,tr[x].ans);return;
}signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endiftr[0].lmax=tr[0].rmax=tr[0].ans=-inf;n=read();for(int i=1;i<n;i++){int x=read(),y=read(),w=read();e[x].push_back(mkp(y,w));e[y].push_back(mkp(x,w));}tot=n+n;dfs0(1,0);dfs1(1);int rt=dfs2(1,0);for(int i=n+1;i<=tot;i++) ban[i]=1;init(rt);if(Flag) for(int i=1;i<=tot;i++) printf("i=%d dep=%d\n",i,dep[i]);m=read();char c;for(int i=1;i<=m;i++){scanf(" %c",&c);if(c=='A'){if(tr[rt].ans<0) puts("They have disappeared.");else printf("%d\n",tr[rt].ans);}else{int x=read();ban[x]^=1;for(;x;x=tr[x].fa) pushup(x);}if(Flag) init(rt);if(Flag) puts("");}return 0;
}
/*
5
1 2 -8
2 3 -5
1 4 -7
4 5 -6*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[CodeJam 2021 Round 3] Square Free(调整法 / 字典序最小解网络流)

CodeJam 2021 Round3 Square Freeproblemsolutioncodecode-stdproblem 神奈子是个很爱打麻将的老婆婆&#xff0c;有一天她把她的麻将放进了一个 nmn\times mnm 的网格图里&#xff0c;每个麻将可以左斜着放入网格中&#xff08;如 / &#xff09;&#xff0c;也可以右斜着&am…

P6773 [NOI2020] 命运(dp、线段树合并)

前言 一道看起来很毒瘤但其实还算小清新的题&#xff1f; 理解后感觉其实并没有那么难。 暴力分非常足&#xff0c;好评。 奇妙的线段树合并技巧增加了。 解析 解法1 你是怎么手玩的样例一&#xff1f; 大部分&#xff08;比如我&#xff09;都是容斥吧。 把手玩的方法搬到…

ConsurrentDictionary并发字典知多少?

在上一篇文章你真的了解字典吗?一文中我介绍了Hash Function和字典的工作的基本原理.有网友在文章底部评论,说我的Remove和Add方法没有考虑线程安全问题.https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?redirectedfromMSDN&viewn…

[luogu 4292][bzoj 1758][WC2010] 重建计划(点分治 + dp + 单调队列优化 + 启发式合并)

[WC2010]重建计划problemsolutioncodeproblem 洛谷指路 solution 一看那个道路平均价值的式子&#xff1a;AvgValue∑e∈Sv(e)∣S∣\text{AvgValue}\frac{\sum_{e\in S}v(e)}{|S|}AvgValue∣S∣∑e∈S​v(e)​ 就是 0/1分数规划 的样子。 所以考虑二分最终的答案 midmidmid…

cf1553C. Penalty

cf1553C. Penalty 题意&#xff1a; 有十轮点球&#xff0c;两个队伍轮流进行&#xff0c;1表示进&#xff0c;0表示不进&#xff0c;&#xff1f;表示未知&#xff0c;如果比赛没有了悬念将直接结束。现在让你预测一个情况&#xff0c;使得进行的轮数最少。裁判在决定停止点…

ASP.NET Core 基于JWT的认证(二)

上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍&#xff0c;这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用。.Net Core 2.2Visual Studio 2017ASP.NET Core WebAPI2在上一篇文章中&#xff0c;我们详细的介绍了JWT的知识&#xff0c;这…

P6774 [NOI2020] 时代的眼泪(分块)

前言 看到题目名&#xff1a;别骂了别骂了。 一道很中规中矩的YNOI吧。 卡在整块对整块的贡献上了。 这也确实算是本题最不好做的部分了。 前置知识&#xff1a;Yuno loves sqrt technology I 解析 区间逆序对加强版&#xff1f;很难不想到两道 YLST。 然而多了两维限制&a…

[NOIP2021] 数列(计数dp)

solution f[i][j][k][num][p]:2pf[i][j][k][num][p]:2^pf[i][j][k][num][p]:2p 选择了 iii 个&#xff0c;前 p−1p-1p−1 位 (202p−1)(2^0~2^{p-1})(20 2p−1) 已经选了jjj个&#xff0c;低位向高位进位上来 kkk&#xff0c;前 ppp 位已经确定有 numnumnum 个位置为 111&…

Xor sum HDU - 6955

Xor sum HDU - 6955 题意&#xff1a; 给定一个长度为n的整数序列&#xff0c;求其XOR和不小于k的最短连续子序列。 如果有多个相同长度的连续子序列&#xff0c;则打印具有最小左端点的连续子序列。 如果没有连续的子序列开关XOR总和不小于k&#xff0c;只需打印“-1”。 …

模板:子序列自动机(字符串)

所谓子序列自动机&#xff0c;就是根据子序列建立的自动机。 &#xff08;逃&#xff09; 前言 小清新算法。 解析 和其他自动机类似的&#xff0c;我们希望子序列自动机能且只能接受原串的所有子序列。 考虑一个问题&#xff1a;给你一个串 T&#xff0c;如何判断它是否是…

Docker最全教程之Go实战,墙裂推荐(十九)

前言与其他语言相比&#xff0c;Go非常值得推荐和学习&#xff0c;真香&#xff01;为什么&#xff1f;主要是可以直接编译成机器代码&#xff08;性能优越&#xff0c;体积非常小&#xff0c;可达10来M&#xff0c;见实践教程图片&#xff09;而且设计良好&#xff0c;上手门槛…

[BZOJ3093][Fdu校赛2012] A Famous Game(不等概率)

problem BOZJ3093 solution 逆概率公式&#xff0c;即贝叶斯(Bayes)公式&#xff1a; 假设 B1,B2,...,BnB_1,B_2,...,B_nB1​,B2​,...,Bn​ 是 Ω\OmegaΩ 的一个分割&#xff0c;P(A)>0P(A)>0P(A)>0&#xff0c;则有 P(Bk∣A)P(ABk)P(A)P(Bk)P(A∣Bk)∑i1nP(Bi)…

Mod, Or and Everything HDU - 6950

Mod, Or and Everything HDU - 6950 题意&#xff1a; 给你一个n,问(n%1) or (n%2) or … or (n %n)的值 题解&#xff1a; 无论n为奇偶&#xff0c;定义m(n-1)/2&#xff0c; 我们发现n mod i<m&#xff0c;而当i<m时&#xff0c;有n mod (n-i) i ,于是就有n mod i …

你注意到 .Net Framework 和 .Net Core 中使用 Session 的区别了吗?

在测试一个例子时发现的问题&#xff0c;这个示例实现的功能是刷新页面也能保持表格锁定列的状态&#xff0c;先看下页面的完成效果&#xff1a;测试中发现&#xff0c;几乎相同的代码&#xff1a;在 FineUIMvc&#xff08;Net Framework&#xff09;下没有问题&#xff1a;htt…

模板:拉格朗日乘子法(数学)

所谓拉格朗日乘子法&#xff0c;就是拉格朗日发明的乘子法。 &#xff08;逃&#xff09; 前言 曾经&#xff0c;我被它爆杀&#xff1b;如今&#xff0c;不同的日子&#xff0c;同样的题目&#xff0c;我却不再是曾经的我了。 因为我写模拟退火了。 也不能老是这么混着&…

[UOJ299][CTSC2017] 游戏

【CTSC2017】游戏 problem UOJ299 solution 定义 Xi:X_i:Xi​: 当前已知条件第 iii 局的状态 1/01/01/0&#xff08;胜/败&#xff09;。 将 XiCiX_iC_iXi​Ci​ 记为事件 AiA_iAi​。 假设现在已知条件共有 sss 个&#xff0c;即&#xff1a;第 k1∼sk_{1\sim s}k1∼s​…

Alice and Bob

Alice and Bob 题意&#xff1a; 两人博弈&#xff0c;每次一个人从一堆中拿k个&#xff0c;同时从另一堆拿k * s(s>0)个&#xff0c;问谁先不能拿 10000组数据,N<5000 题解&#xff1a; (x,y)表示第一堆石头数量为x&#xff0c;第二堆为y 如果(x,y)是必败状态&#…

一键发布部署vs插件[AntDeploy]开源了

deploy to remote server by one button click功能支持docker一键部署(支持netcore)支持iis一键部署(支持netcore和framework)(支持增量发布)(支持一键回滚)(支持点火)支持windows服务一键部署(支持netcore和framework)(支持增量发布)(支持一键回滚) 使用插件前我要发布一个net…

CF1257F Make Them Similar(meet in the middle,模拟退火)

前言 sto 退火大师_slb orz sto 正解大师_KHIN orz 只有我啥也不会&#xff0c;哈哈。 有趣的是&#xff0c;两种方法我都想到了一部分&#xff0c;然后都寄掉了。 这有趣个锤子。 解析 Sol1 考虑枚举最终的popcount&#xff0c;然后限制就变成了一个类似于高斯消元的形式…

Find 3-friendly Integers

Find 3-friendly Integers 题意&#xff1a; 定义一个自然数是精妙的&#xff0c;如果他存在一个字串(允许前导0)是3的倍数 问L到R中精妙的数的个数 题解&#xff1a; 数位dp可以做(但我不会。。。) 用结论来做&#xff0c;当n>100时(即为3位数时)必然是精妙的数&#x…