• [BZOJ4817][SDOI2017]树点涂色


    BZOJ
    Luogu

    sol

    这个题只要你想清楚了就变成码农题了。
    你会发现操作1神似(LCT)中的(access)
    考虑在某一次1操作中,会有若干组父子关系,有的是父子从同色变成了异色,有的是从异色变成了同色。如果我们就把同色的点放在一棵splay里面,那操作就直接对应(access)操作了。
    我们考虑维护这个东西:每个点到根的路径权值(val_i)
    如果一对父子的颜色从同色变成异色,那么原树中以那个儿子为根的子树的每个点的权值都会加一;反之,若从异色变同色,那么就会全部减一。而对应到(access)中,由同变异的刚好是原实儿子,由异变同的刚好是新实儿子。
    子树转化成区间,然后就是经典线段树操作。
    对于操作2,答案是(val_x+val_y-2*val_{lca(u,v)}+1)
    所以你需要写LCA+LCT+支持区间加和区间查最大值的线段树

    注意:在(access)中,打标记的位置是链顶
    所以要在splay中暴跳一下左儿子找到最左边那个点

    code

    LCA沉迷树链剖分无法自拔
    线段树可以标记永久化
    LCT只要写(access),连(rev)都不用打

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 100005;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    struct edge{int to,next;}a[N<<1];
    int n,m,head[N],cnt,pa[N],dep[N],sz[N],son[N],top[N],dfn[N],low[N];
    void dfs1(int u,int f)
    {
    	pa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    	for (int e=head[u];e;e=a[e].next)
    	{
    		int v=a[e].to;if (v==f) continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int up)
    {
    	top[u]=up;dfn[u]=++cnt;
    	if (son[u]) dfs2(son[u],up);
    	for (int e=head[u];e;e=a[e].next)
    		if (a[e].to!=pa[u]&&a[e].to!=son[u])
    			dfs2(a[e].to,a[e].to);
    	low[u]=cnt;
    }
    int getlca(int u,int v)
    {
    	while (top[u]^top[v])
    	{
    		if (dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=pa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int tag[N<<2],mx[N<<2];
    void Modify(int x,int l,int r,int ql,int qr,int v)
    {
    	if (l>=ql&&r<=qr)
    	{
    		tag[x]+=v;mx[x]+=v;
    		return;
    	}
    	int mid=l+r>>1;
    	if (ql<=mid) Modify(x<<1,l,mid,ql,qr,v);
    	if (qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,v);
    	mx[x]=max(mx[x<<1],mx[x<<1|1])+tag[x];
    }
    int Query(int x,int l,int r,int ql,int qr)
    {
    	if (l>=ql&&r<=qr) return mx[x];
    	int mid=l+r>>1,s=-1e9;
    	if (ql<=mid) s=max(s,Query(x<<1,l,mid,ql,qr));
    	if (qr>mid) s=max(s,Query(x<<1|1,mid+1,r,ql,qr));
    	return s+tag[x];
    }
    int fa[N],ls[N],rs[N];
    bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    void R_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	ls[y]=rs[x];
    	if (rs[x]) fa[rs[x]]=y;
    	fa[x]=z;
    	if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    	rs[x]=y;fa[y]=x;
    }
    void L_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	rs[y]=ls[x];
    	if (ls[x]) fa[ls[x]]=y;
    	fa[x]=z;
    	if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    	ls[x]=y;fa[y]=x;
    }
    void splay(int x)
    {
    	while (!isroot(x))
    	{
    		int y=fa[x],z=fa[y];
    		if (isroot(y))
    			if (x==ls[y]) R_rotate(x);
    			else L_rotate(x);
    		else
    			if (y==ls[z])
    				if (x==ls[y]) R_rotate(y),R_rotate(x);
    				else L_rotate(x),R_rotate(x);
    			else
    				if (x==ls[y]) R_rotate(x),L_rotate(x);
    				else L_rotate(y),L_rotate(x);
    	}
    }
    int getf(int x){while(ls[x])x=ls[x];return x;}
    void access(int x)
    {
    	int gg;
    	for (int y=0;x;y=x,x=fa[x])
    	{
    		splay(x);
    		if (rs[x]) gg=getf(rs[x]),Modify(1,1,n,dfn[gg],low[gg],1);
    		if (y) gg=getf(y),Modify(1,1,n,dfn[gg],low[gg],-1);
    		rs[x]=y;
    	}
    }
    int main()
    {
    	n=gi();m=gi();
    	for (int i=1,u,v;i<n;i++)
    	{
    		u=gi();v=gi();
    		a[++cnt]=(edge){v,head[u]};head[u]=cnt;
    		a[++cnt]=(edge){u,head[v]};head[v]=cnt;
    	}
    	dfs1(1,0);cnt=0;dfs2(1,1);
    	for (int i=1;i<=n;i++) fa[i]=pa[i],Modify(1,1,n,dfn[i],low[i],1);
    	while (m--)
    	{
    		int opt=gi(),x=gi(),y,gg;
    		if (opt==1) access(x);
    		if (opt==2)
    		{
    			y=gi();
    			gg=getlca(x,y);
    			printf("%d
    ",Query(1,1,n,dfn[x],dfn[x])+Query(1,1,n,dfn[y],dfn[y])-2*Query(1,1,n,dfn[gg],dfn[gg])+1);
    		}
    		if (opt==3) printf("%d
    ",Query(1,1,n,dfn[x],low[x]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    伪元素和伪类的区别
    绝对定位是相对定位元素的什么边界进行定位的?
    元素如何设置滚动/滚动条的设置与隐藏
    什么是行内元素、块级元素?
    通过JS判断当前浏览器的类型
    获取元素计算样式getComputedStyle()与currentStyle
    javascript链式运动框架案例
    任意值的运动框架
    JS多物体运动案例:变宽、变高
    offsetWidth与offsetHeight
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8334926.html
Copyright © 2020-2023  润新知