CF1137F Matches Are Not a Child's Play

一、题目

点此看题

二、解法

思维含量和代码难度都点满了,但是我喜欢写这种码农题(除了插头 \(dp\))😅

问题很简单,就是每次把某个节点编号变为最大的情况下维护出这个删除序列。那么我们考虑这个操作有什么特别的性质,就让小编来带你们看看吧

无根树问题可以优先考虑定根,本题可以考虑设置编号最大的点为根,那么根一定是最后删除的。假如此时我们 up u,那么 \(u\) 到根路径的点会成为最后一个、倒数第二个、倒数第三个\(...\)也就是我们把路径上的点取出来移动到序列末尾,然后其它点的删除顺序不变。

修改某个点到根路径可以考虑 \(\tt lct\),而我们此时可以套用染色模型,也就是修改看成某个点到根的染色,然后实边代表颜色相同,虚边代表颜色不同。那么初始的树可以依次按编号从大到小染色,遇到已经被染色的节点就停止,对于修改 up v 相当于用一种最大的新颜色处理它到根的路径。

那么我们考虑如何通过染色来得到一个点在删除序列中的位置呢?发现就是颜色比它小的点个数 和 与它同色并且和深度比它大的点个数。第一部分可以用树状数组维护,在 \(\tt access\) 的时候在上面修改一个颜色对应的个数即可,第二部分就是在它所在的同色链中计算即可。

时间复杂度 \(O(n\log n)\),常数因为树状数组特别地小。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,UP,tot,f[M],b[M<<1];char zxy[10];
int st[M],ch[M][2],siz[M],fa[M],col[M],cv[M],fl[M];
struct edge
{
	int v,next;
}e[M<<1];
//tree-array
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int c)
{
	for(int i=x;i<=UP;i+=lowbit(i))
		b[i]+=c;
}
int ask(int x)
{
	int r=0;
	for(int i=x;i>=1;i-=lowbit(i))
		r+=b[i];
	return r;
}
//link-cut-tree
int nrt(int x)
{
	return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
int chk(int x)
{
	return ch[fa[x]][1]==x;
}
void up(int x)
{
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void flip(int x)
{
	if(!x) return ;
	swap(ch[x][0],ch[x][1]);fl[x]^=1;
}
void cover(int x,int c)
{
	if(!x) return ;
	col[x]=cv[x]=c;
}
void down(int x)
{
	if(fl[x])
		flip(ch[x][0]),flip(ch[x][1]),fl[x]=0;
	if(cv[x])
		cover(ch[x][0],cv[x]),cover(ch[x][1],cv[x]),cv[x]=0;
}
void rotate(int x)
{
	int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
	ch[y][k]=w;fa[w]=y;
	if(nrt(y)) ch[z][chk(y)]=x;fa[x]=z;
	ch[x][k^1]=y;fa[y]=x;
	up(y);up(x);
}
void splay(int x)
{
	int y=x,k=0;st[k=1]=x;
	while(nrt(y)) y=fa[y],st[++k]=y;
	while(k) down(st[k--]);
	while(nrt(x))
	{
		int y=fa[x];
		if(nrt(y))
		{
			if(chk(x)==chk(y)) rotate(y);
			else rotate(x);
		}
		rotate(x);
	}
}
void access(int x)//modified version
{
	int u=x;++k;
	for(int y=0;x;x=fa[y=x])
	{
		splay(x);ch[x][1]=0;up(x);
		add(col[x],-siz[x]);ch[x][1]=y;up(x);
	}
	splay(u);cover(u,k);flip(u);
	add(col[u],siz[u]);
}
int qry(int x)
{
	splay(x);
	return ask(col[x]-1)+siz[ch[x][1]]+1;
}
//dfs & initialize
void dfs(int u,int p)
{
	fa[u]=p;
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(v==p) continue;
		dfs(v,u);
	}
}
signed main()
{
	n=read();m=read();k=n;UP=n+m;
	for(int i=1;i<=n;i++) siz[i]=1;
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		e[++tot]=edge{v,f[u]},f[u]=tot;
		e[++tot]=edge{u,f[v]},f[v]=tot;
	}
	dfs(n,0);
	for(int i=n,nw=n;i>=1;i--)
	{
		if(col[i]) continue;
		int u=i,cnt=0,v=0;
		while(!col[u] && u)
			col[u]=nw,ch[u][1]=v,up(u),
			v=u,u=fa[u],cnt++;
		add(nw,cnt);nw--;
	}
	while(m--)
	{
		scanf("%s",zxy);
		if(zxy[0]=='u')
			access(read());
		if(zxy[0]=='w')
			printf("%d\n",qry(read()));
		if(zxy[0]=='c')
		{
			int u=read(),v=read();
			if(qry(u)<qry(v)) printf("%d\n",u);
			else printf("%d\n",v);
		}
	}
}
posted @ 2022-01-03 16:20  C202044zxy  阅读(122)  评论(0编辑  收藏  举报