题意:一棵树,点有$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));
		}
	}
}

[xsy2913]enos的更多相关文章

  1. 【xsy2913】 enos 动态dp

    题目大意:给你一棵 $n$个点 以 $1$为根 的树,每个点有$ 0,1,2 $三种颜色之一,初始时整棵树的颜色均为 $0$. $m$ 次操作, 每次操作形如: 1 x y c : 将 $x$到$y$ ...

  2. ng-table 简单实例

    今天用的AngularJs需要做个分页,于是用ng-table去实现,不过这个官网感觉有点坑,说的不够清楚. 下面实现了一个Demo实力,代码如下: <!DOCTYPE html> < ...

  3. AngularJs 动态加载模块和依赖

    最近项目比较忙额,白天要上班,晚上回来还需要做Angular知识点的ppt给同事,毕竟年底要辞职了,项目的后续开发还是需要有人接手的,所以就占用了晚上学习的时间.本来一直不打算写这些第三方插件的学习笔 ...

  4. ui-grid

    html代码: <html ng-app="myApp">       <head>         <meta charset="utf- ...

  5. [转]ng-grid

    本文转自:http://angular-ui.github.io/ui-grid/ Getting Started Steps for getting started (example on righ ...

  6. IGS_学习笔记10_IREP监控SOA Integration和日志设定(案例)

    20150506 Created By BaoXinjian

  7. CentOS7.1 使用资源搜集

    1.配置java环境 -openjdk* 测试 java -version 2.安装Tomcat8.0.35 点击题目可以参考源网页,但有些代码无法执行,更改如下(亲测可行): 一定要先安装java环 ...

  8. [转帖][超级少儿不宜]一氧化氮(NO),为什么亚洲人是最硬

    阴茎科学:一氧化氮(NO),为什么亚洲人是最硬 尼堪巴图鲁   ​关注他 2,911 人赞同了该文章   https://zhuanlan.zhihu.com/p/55941740 超级少儿不宜.. ...

  9. 物联网全景动态图谱2.0|PaaS物联网平台汇总(上篇)

    物联网智库 原创 物联网智库 整理发布 转载请注明来源和出处 ------   [导读]   ------ 毫无疑问,2018年物联网对行业的深度变革才刚刚开启. 物联网产业链企业的质与量将进入全面爆 ...

随机推荐

  1. Linux操作系统介绍

    1Linux操作系统介绍 1.1linux系统的应用 服务器系统:Web应用服务器.数据库服务器.接口服务器.DNS.FTP等等: 嵌入式系统:路由器.防火墙.手机.PDA.IP 分享器.交换器.家电 ...

  2. .NET 4.5 Task异步编程学习资料

    参考资料: 1. http://www.cnblogs.com/heyuquan/archive/2013/04/18/3028044.html

  3. iconfont-矢量图标字体

    二.矢量图标使用 1.进入:http://www.iconfont.cn/  搜索你图标的关键字,然后将需要的图标字体加入购物车 加入购物车之后,添加到项目 2.点击查看在线连接,生成css代码,把代 ...

  4. IntelliJ IDEA 里 查看一个函数注释的方法是 ctrl+q

     ctrl + q 也可以看到 官方的文档注释,java真是个强大的东西,官方的每个函数都有注释,这些注释 自动生成了官方的文档,所以看官方的注释 就是 看 官方的文档.

  5. Oracle学习笔记:decode函数

    decode函数主要作用:将查询结果翻译成其他值(即以其他形式变现出来) 使用方法: SELECT DECODE(colunm_name,值1,翻译值1,值2,翻译值2……值n,翻译值n,缺省值) F ...

  6. MySQL学习笔记:while循环

    思考:while循环是否只能使用在存储过程或者存储函数之中,不能直接在查询语句中使用? ———— 循环一般在存储过程和存储函数中使用. 直接放几个例子: 例一: 1.创建存储过程 DELIMITER ...

  7. 微信小程序蓝牙模块

    蓝牙部分知识 关于Service: 每个设备包含有多个Service,每个Service对应一个uuid 关于Characteristic 每个Service包含多个Characteristic,每个 ...

  8. NSPredicate用法总结(Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取)

    简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 定义(最常用到的方法): NSPredicate *ca = [NSPred ...

  9. CCF CSP 201604-4 游戏

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201604-4 游戏 问题描述 小明在玩一个电脑游戏,游戏在一个n×m的方格图上进行,小明控制 ...

  10. lr参数化取值与连接数据库

    TXT文本,EXCEL表格以及数据库中的表都可以作为参数的数据集载体,LR都是支持的. 特别提醒: 1.在形成数据池之后,数据库中的数据变化不会影响数据池中的数据. 2.数据文件一定要以一个空行结束, ...