CF13E Holes

题目链接

题意分析

看这篇题解 默认你已经会LCT并且明白如何使用了

说实在的 这题跟【P3203 [HNOI2010]弹飞绵羊】简直如出一辙

首先 我们根据题意可以得到一棵树

如果i+power[i]≤n的话 那么i+power[i]就是i的父亲

否则就令n+1是i的父亲

可以发现 n+1就是这棵树的根节点

修改我们可以看作动态的删连边 所以就用了LCT

至于查询的话 我们先得到从x到n+1的链

弹了几次 就是这条链上除了n+1之外剩余点的个数 就是Splay的size

弹走之前最后一个点 就是这条链上除了n+1之外点的最大值 我们可以使用链上最大值维护

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define M 1008611
using namespace std;
int n,m,top,fly;
struct LCT
{
	int son[2],fa,siz,val,maxn;
	bool tag;
}tre[M];
int power[M],sta[M];
bool isroot(int x)
{return !((tre[tre[x].fa].son[0]==x)||(tre[tre[x].fa].son[1]==x));}
void pushup(int x)
{//对于size以及最大值的维护
	tre[x].siz=tre[tre[x].son[0]].siz+tre[tre[x].son[1]].siz+1;
	if(tre[x].val!=fly) tre[x].maxn=max(tre[x].val,max(tre[tre[x].son[0]].maxn,tre[tre[x].son[1]].maxn));
	else tre[x].maxn=max(tre[tre[x].son[0]].maxn,tre[tre[x].son[1]].maxn);
}
void down(int x)
{
	if(tre[x].tag)
	{
		if(tre[x].son[0]) tre[tre[x].son[0]].tag^=1;
		if(tre[x].son[1]) tre[tre[x].son[1]].tag^=1;
		tre[x].tag=0;
		swap(tre[x].son[0],tre[x].son[1]);	
	}
} 
void rotate(int x)
{
	int fat=tre[x].fa,fatt=tre[tre[x].fa].fa;
	int d=(tre[tre[x].fa].son[1]==x);
	int tson=tre[x].son[d^1];
	if(!isroot(fat)) tre[fatt].son[tre[fatt].son[1]==fat]=x;
	tre[x].fa=fatt;tre[x].son[d^1]=fat;tre[fat].fa=x;tre[fat].son[d]=tson;
	if(tson) tre[tson].fa=fat;
	pushup(fat);pushup(x);
}
void Splay(int x)
{
	int cdy=x,wzy;top=0;
	sta[++top]=cdy;
	while(!isroot(cdy)) sta[++top]=cdy=tre[cdy].fa;
	while(top>0) down(sta[top--]);
	while(!isroot(x))
	{
		cdy=tre[x].fa;wzy=tre[tre[x].fa].fa;
		if(!isroot(cdy))
		{
			if((tre[cdy].son[1]==x)^(tre[wzy].son[1]==cdy)) rotate(x);
			else rotate(cdy);
		}
		rotate(x);
	}
	pushup(x);
}
void access(int x)
{
	for(int now=0;x;x=tre[now=x].fa)
	{
		Splay(x);tre[x].son[1]=now;pushup(x);
	}
}
void makeroot(int x)
{
	access(x);Splay(x);tre[x].tag^=1;
}
void split(int x,int y)
{
	makeroot(x);access(y);Splay(y);;
}
void link(int x,int y)
{
	makeroot(x);
	tre[x].fa=y; 
}
void cut(int x,int y)
{
	split(x,y);
	tre[x].fa=tre[y].son[0]=0;
	return;
}
int main()
{
	scanf("%d%d",&n,&m);fly=n+1;//fly就是所有飞出去的到达的位置 
	for(int i=1;i<=n;++i) scanf("%d",&power[i]),tre[i].val=i;
	for(int i=1;i<=n;++i)
	{
		int x=i,y=min(fly,i+power[i]);
		link(x,y);
	}
	for(int i=1,knd,x,y;i<=m;++i)
	{
		scanf("%d",&knd);
		if(knd==0)
		{
			scanf("%d%d",&x,&y);
			int fro=min(fly,x+power[x]),to=min(fly,x+y);
			cut(x,fro);link(x,to);
			power[x]=y;
		}
		else
		{
			scanf("%d",&x);
			makeroot(x);
			access(fly);
			Splay(fly);
			printf("%d %d\n",tre[fly].maxn,tre[fly].siz-1);
		}
		
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章