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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章