题目链接
题意分析
看这篇题解 默认你已经会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
",tre[fly].maxn,tre[fly].siz-1);
}
}
return 0;
}