[xsy2913]enos

编程入门 行业动态 更新时间:2024-10-13 08:21:47

[xsy2913]enos

[xsy2913]enos

题意:一棵树,点有$0,1,2$三种颜色,支持路径修改颜色和查询点所在同色连通块的大小

lcm太可怕了,于是去问了sk,得到一个优质做法

考虑lct维护子树信息,$vs_{x,i}$为$x$的虚儿子中,以颜色为$i$的节点为根的同色连通块大小之和,$s_{x,i}$表示splay上$x$的子树$vs_{x,i}$之和,切换虚实时更新$vs$,splay上pushup时更新$s$即可

如果每时每刻都保持同一棵splay中点的颜色都相同,那么询问时只需模仿access的过程,不停往上拼接同色splay,最后得到的splay的根节点$x$的$s_{x,c_x}+siz_x$就是答案,我们把这种access称为按颜色access

现在考虑修改,先求lca,把修改拆成两个祖先后代链,假设这条祖先后代链为$y\rightarrow x$,$y$是$x$的祖先

先对$fa_y$按颜色access,再对$x\rightarrow y$无条件access,对得到的splay打标记即可

这棵splay可能会作为某个点的虚儿子,看起来要一直往上更新,实际上最多更新往上的两棵splay即可

设往上的三棵splay为$T_1,T_2,T_3$,因为$T_1$是按颜色access得到的,所以$c_{T_1}\neq c_{T_2}$

首先$T_1$显然需要更新,然后因为$T_2$需要用到$T_1$的信息,所以当$y\rightarrow x$这条链在修改前或修改后的颜色$=c_{T_1}$时,$T_1$的$s_{x,c_{T_1}}$会变化,进而影响$T_2$的$s_{x,c_{T_1}}$

幸运地,$T_3$只需要用到$T_2$的$s_{x,c_{T_2}}$信息,又因为$c_{T_1}\ne c_{T_2}$,所以从$T_3$开始往上的那些splay都无需更新

最后是无条件access所引发的一些小问题,在按颜色access时,我们可以快速而准确地更新一个节点的$vs$,但无条件access时,splay中可能含有不同颜色的点,这时不能直接用$s_{x,c_x}+siz_x$来计算$x$对父亲的$vs$的贡献

解决方法很简单:在拼接$x$和$y$之前先算出$x$对父亲的旧贡献,减掉即可,又因为一个节点原来的实儿子的splay子树中都是同颜色的点,这部分的贡献可以直接按原来的方法算

于是整道题就做完了,这个题还是挺好的==

再次orzskdtz两位人形自走dspedia

#include<stdio.h>
#include<algorithm>
using namespace std;
int n;
namespace t{int h[100010],nex[100010],to[100010],M;void add(int a,int b){M++;to[M]=b;nex[M]=h[a];h[a]=M;}int fa[100010][17],dep[100010],siz[100010];void dfs(int x){dep[x]=dep[fa[x][0]]+1;siz[x]=1;for(int i=h[x];i;i=nex[i]){if(to[i]!=fa[x][0]){dfs(to[i]);siz[x]+=siz[to[i]];}}}void work(){int i,j;for(i=2;i<=n;i++){scanf("%d",fa[i]);add(fa[i][0],i);}dfs(1);for(j=1;j<17;j++){for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];}}int lca(int x,int y){int i;if(dep[x]<dep[y])swap(x,y);for(i=16;i>=0;i--){if(dep[fa[x][i]]>=dep[y])x=fa[x][i];}if(x==y)return x;for(i=16;i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];}
}
namespace l{int ch[100010][2],fa[100010],r[100010],siz[100010],s[100010][3],vs[100010][3],d[100010],c[100010];#define ls ch[x][0]#define rs ch[x][1]void pushup(int x){for(int i=0;i<3;i++)s[x][i]=s[ls][i]+s[rs][i]+vs[x][i];r[x]=rs?r[rs]:x;siz[x]=siz[ls]+siz[rs]+1;}void rot(int x){int y,z,f,b;y=fa[x];z=fa[y];f=ch[y][0]==x;b=ch[x][f];fa[x]=z;fa[y]=x;if(b)fa[b]=y;ch[x][f]=y;ch[y][f^1]=b;if(ch[z][0]==y)ch[z][0]=x;if(ch[z][1]==y)ch[z][1]=x;pushup(y);pushup(x);}void set(int x,int v){d[x]=c[x]=v;}void pushdown(int x){if(~d[x]){if(ls)set(ls,d[x]);if(rs)set(rs,d[x]);d[x]=-1;}}bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}void gao(int x){if(!isrt(x))gao(fa[x]);pushdown(x);}void splay(int x){gao(x);int y,z;while(!isrt(x)){y=fa[x];z=fa[y];if(!isrt(y))rot((ch[z][0]==y)^(ch[y][0]==x)?x:y);rot(x);}}void work(){int i;for(i=1;i<=n;i++){fa[i]=t::fa[i][0];r[i]=i;d[i]=-1;siz[i]=1;vs[i][0]=s[i][0]=t::siz[i]-1;}}#define v(x) (s[x][c[x]]+siz[x])void access(int x,int z){int y,t;splay(x);y=0;t=0;while(x){splay(x);if(r[x]==z)break;vs[x][c[rs]]+=v(rs);vs[x][c[y]]-=t;t=v(x);rs=y;pushup(x);y=x;x=fa[x];}}int query(int x){int y,v;splay(x);y=0;v=c[x];while(x){splay(x);if(c[x]!=v)break;vs[x][c[rs]]+=v(rs);vs[x][c[y]]-=v(y);rs=y;pushup(x);y=x;x=fa[x];}return s[y][v]+siz[y];}
}
void modify(int x,int y,int v){using namespace l;int z=t::fa[y][0];if(z){query(z);splay(z);if(fa[z]){splay(fa[z]);vs[fa[z]][c[z]]-=v(z);}splay(y);vs[z][c[y]]-=v(y);}access(x,z);splay(x);set(x,v);if(z){splay(y);vs[z][c[y]]+=v(y);pushup(z);if(fa[z]){vs[fa[z]][c[z]]+=v(z);pushup(fa[z]);}}
}
int main(){int m,i,x,y,z,k;scanf("%d%d",&n,&m);t::work();l::work();while(m--){scanf("%d",&i);if(i==1){scanf("%d%d%d",&x,&y,&z);k=t::lca(x,y);modify(x,k,z);modify(y,k,z);}else{scanf("%d",&x);printf("%d\n",l::query(x));}}
}

转载于:.html

更多推荐

[xsy2913]enos

本文发布于:2024-03-23 18:35:20,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1741451.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:enos

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!