zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 2243 [SDOI2011]染色

    Description

    给定一棵有n个节点的无根树和m个操作,操作有2类:

    1、将节点a到节点b路径上所有点都染成颜色c;

    2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),

    如“112221”由3段组成:“11”、“222”和“1”。

    请你写一个程序依次完成这m个操作。

    Input

    第一行包含2个整数n和m,分别表示节点数和操作数;

    第二行包含n个正整数表示n个节点的初始颜色

    下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。

    下面 行每行描述一个操作:

    “C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

    “Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

    Output

    对于每个询问操作,输出一行答案。

    Sample Input

    6 5
    2 2 1 2 1 1
    1 2
    1 3
    2 4
    2 5
    2 6
    Q 3 5
    C 2 1 1
    Q 3 5
    C 5 1 2
    Q 3 5

    Sample Output

    3
    1
    2

    HINT

    数N<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。

    Solution

    这题有很多做法,树剖,LCT
    因为现在正在练LCT,所以就用LCT写了
    一条链上,维护四个东西,col(结点本身颜色),lco(结点包括其Splay子树代表的一段颜色的最左边颜色),rco(这个就是最右边的),sum(结点包括其Splay子树代表的一段的答案)
    因为LCT的Splay保证了中序遍历按深度递增,所以一个结点包括其子树后包含的位置一定是连续的一段,所以可以这样维护
    然后对于pushup
    首先直接把两个儿子的sum与自己的长度1全部加上后
    再判断连接的地方是否相同,如果相同就减去多加的(这个地方可能说不清楚,但一看代码就明白了)
    然后当前结点的lco就是左儿子的lco,rco就是右儿子的rco
    还要注意如果没有左右儿子,就千万不要转移,否则会出问题,lco和rco会转移错误

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=100000+10;
    int n,m;
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN][2],fa[MAXN],rev[MAXN],sum[MAXN],lco[MAXN],rco[MAXN],pnt[MAXN],stack[MAXN],cnt,col[MAXN];
    	inline bool nroot(int x)
    	{
    		return lc(fa[x])==x||rc(fa[x])==x;
    	}
    	inline void reverse(int x)
    	{
    		std::swap(lc(x),rc(x));
    		std::swap(lco[x],rco[x]);
    		rev[x]^=1;
    	}
    	inline void paint(int x,int c)
    	{
    		sum[x]=1;
    		pnt[x]=col[x]=lco[x]=rco[x]=c;
    	}
    	inline void pushup(int x)
    	{
    		sum[x]=sum[lc(x)]+sum[rc(x)]+1;
    		if(lc(x)&&rc(x))sum[x]=sum[x]-(rco[lc(x)]==col[x])-(col[x]==lco[rc(x)]);
    		else if(lc(x))sum[x]=sum[x]-(rco[lc(x)]==col[x]);
    		else if(rc(x))sum[x]=sum[x]-(col[x]==lco[rc(x)]);
    		lco[x]=rco[x]=col[x];
    		if(lc(x))lco[x]=lco[lc(x)];
    		if(rc(x))rco[x]=rco[rc(x)];
    	}
    	inline void pushdown(int x)
    	{
    		if(pnt[x])
    		{
    			if(lc(x))paint(lc(x),pnt[x]);
    			if(rc(x))paint(rc(x),pnt[x]);
    			pnt[x]=0;
    		}
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    		pushup(f);
    		pushup(x);
    	}
    	inline void splay(int x)
    	{
    		cnt=0;
    		stack[++cnt]=x;
    		for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
    		while(cnt)pushdown(stack[cnt--]);
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    		pushup(x);
    	}
    	inline void access(int x)
    	{
    		for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    	}
    	inline void makeroot(int x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(int x,int y)
    	{
    		makeroot(x);fa[x]=y;
    	}
    };
    LCT T;
    #undef lc
    #undef rc
    inline void read(int &x)
    {
    	int data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    inline void write(int x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=n;++i)
    	{
    		int color;
    		read(color);
    		T.col[i]=T.lco[i]=T.rco[i]=color;
    		T.sum[i]=1;
    	}
    	for(register int i=1;i<n;++i)
    	{
    		int u,v;
    		read(u);read(v);
    		T.link(u,v);
    	}
    	while(m--)
    	{
    		char opt[2];
    		scanf("%s",opt);
    		if(opt[0]=='C')
    		{
    			int a,b,c;
    			read(a);read(b);read(c);
    			T.split(a,b);T.paint(b,c);
    		}
    		if(opt[0]=='Q')
    		{
    			int a,b;
    			read(a);read(b);
    			T.split(a,b);
    			write(T.sum[b],'
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    QT QQuickView嵌入到QT MDI中
    地理入门-经纬度时区速成总结篇(转)
    Linux下系统时间函数、DST等相关问题总结(转)
    camera接口---MIPI CSI-2接口、DVP接口和FPD-Link III LVDS、GMSL等接口对比(转)
    基于spi FLASH的嵌入式文件系统 littlefs(转)
    PID 温控系统 解决方法(转)
    单相计量芯片RN8209D使用经验分享(转)
    【开源】EasyFlash 新年发布 V4.0 beta 版,完全重写(转)
    在uboot中加入cmd_run命令,运行环境变量(转)
    MPU6050开发 -- 数据分析(转)
  • 原文地址:https://www.cnblogs.com/hongyj/p/8716024.html
Copyright © 2011-2022 走看看