博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【刷题】BZOJ 2243 [SDOI2011]染色
阅读量:5132 次
发布时间:2019-06-13

本文共 3873 字,大约阅读时间需要 12 分钟。

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<=10^5,操作数M<=10^5,所有的颜色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
#define ll long long#define db double#define ld long doubleconst 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 rcinline 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='\0'){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c);}template
inline void chkmin(T &x,T y){x=(y
inline void chkmax(T &x,T y){x=(y>x?y:x);}template
inline T min(T x,T y){return x
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

转载于:https://www.cnblogs.com/hongyj/p/8716024.html

你可能感兴趣的文章
cuda基础
查看>>
virutalenv一次行安装多个requirements里的文件
查看>>
Vue安装准备工作
查看>>
.NET 母版页 讲解
查看>>
Android Bitmap 和 Canvas详解
查看>>
最大权闭合子图
查看>>
oracle 创建暂时表
查看>>
201421410014蒋佳奇
查看>>
导入导出数据库和导入导出数据库表
查看>>
linux下操作mysql
查看>>
【03月04日】A股滚动市盈率PE历史新低排名
查看>>
Xcode5和ObjC新特性
查看>>
jvm slot复用
查看>>
高并发系统数据库设计
查看>>
LibSVM for Python 使用
查看>>
入坑的开始~O(∩_∩)O~
查看>>
Centos 7.0 安装Mono 3.4 和 Jexus 5.6
查看>>
Windows 7 上安装Visual Studio 2015 失败解决方案
查看>>
iOS按钮长按
查看>>
Shell流程控制
查看>>