problem
题目描述
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
输入输出格式
输入格式:
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。
接下来一行有n个正整数,依次为那n个装置的初始弹力系数。
第三行有一个正整数m,
接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。
输出格式:
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
输入输出样例
输入样例#1: 复制
4
1 2 1 1
3
1 1
2 1 1
1 1
输出样例#1: 复制
2
3
说明
对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
analysis
LCT板子题
我们可以建一个 n+1 n + 1 号节点, x x 号节点连到表示号节点就表示被弹飞
若要更改,直接先 cut c u t 再 link l i n k 一波,关键怎么询问弹飞几次呢?暴力splay?
我们可以 makeroot(n+1) m a k e r o o t ( n + 1 ) ,使 n+1 n + 1 号节点变为原LCT的根
接着我们 access(x) a c c e s s ( x ) 后 splay(x,0) s p l a y ( x , 0 ) ,也就是把 x x 旋转到它原来辅助树的根
那么号节点会弹 xsize−1 x s i z e − 1 次被弹飞,但是为什么呢?
由于辅助树按照深度关键字排序,所以x的深度-1就是要被弹飞几次了
所以明显正确
code
#include<stdio.h>
#include<string.h>
#define MAXN 200001
using namespace std;
int t[MAXN][2];
int b[MAXN],fa[MAXN],pf[MAXN],st[MAXN];
int n,m;
struct node
{
int size,rev;
}a[MAXN];
int min(int x,int y)
{
return x<y?x:y;
}
void swap(int &x,int &y)
{
int z=x;
x=y;
y=z;
}
void change(int x)
{
if(x)
{
a[x].rev^=1;
swap(t[x][0],t[x][1]);
}
}
void down(int x)
{
if (a[x].rev)
{
change(t[x][0]),change(t[x][1]);
a[x].rev=0;
}
}
void update(int x)
{
if(x)
{
a[x].size=a[t[x][0]].size+a[t[x][1]].size+1;
}
}
void downdata(int x)
{
while (x)st[++st[0]]=x,x=fa[x];
while (st[0])down(st[st[0]--]);
}
int lr(int x)
{
return t[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x],k=lr(x);
t[y][k]=t[x][!k];
if(t[x][!k])fa[t[x][!k]]=y;
fa[x]=fa[y];
if(fa[y])t[fa[y]][lr(y)]=x;
t[x][!k]=y;
fa[y]=x;
pf[x]=pf[y];
update(y),update(x);
}
void splay(int x, int y)
{
downdata(x);
while(fa[x]!=y)
{
if(fa[fa[x]]!=y)
{
if(lr(x)==lr(fa[x]))rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
}
void access(int x)
{
for (int y=0;x;update(x),y=x,x=pf[x])
{
splay(x,0);
fa[t[x][1]]=0;
pf[t[x][1]]=x;
t[x][1]=y;
fa[y]=x;
pf[y]=0;
}
}
void makeroot(int x)
{
access(x);
splay(x,0);
change(x);
}
void link(int x, int y)
{
makeroot(x);
pf[x]=y;
}
void cut(int x, int y)
{
makeroot(x);
access(y);
splay(y,0);
t[y][0]=fa[x]=pf[x]=0;
update(y);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
link(i,min(n+1,i+b[i]));
}
scanf("%d",&m);
while (m--)
{
int z,x;
scanf("%d%d",&z,&x),x++;
if (z==1)
{
makeroot(n+1);
access(x);
splay(x,0);
printf("%d\n",a[x].size-1);
}
else
{
cut(x,min(x+b[x],n+1));
scanf("%d",&b[x]);
link(x,min(x+b[x],n+1));
}
}
}

410

被折叠的 条评论
为什么被折叠?



