您的位置:首页 > 其它

bzoj2002Bounce 弹飞绵羊 动态树(Link-Cut-Tree)

2017-09-14 20:23 246 查看

2002: [Hnoi2010]Bounce 弹飞绵羊

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 11830  Solved: 5986

[Submit][Status][Discuss]

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

4

1 2 1 1

3

1 1

2 1 1

1 1

Sample Output

2

3

HINT

Source

题目大意:动态修改询问一个点到链尾的距离。

裸的动态树。

其实可以不裸。

考虑修改,Link的时候,我们考虑把点怼到辅助树的根的时候,左边是他的爸爸们,也就是从这个点到链尾的所与节点。这个时候,需要把它和后面的链点断开,所以直接在辅助树上把它和它的左子树断开(记得儿子父亲都要断)。然后重新连链就可以了。酱紫的话,连rev,makeroot,cut,pushdown什么的都不用啦,效率还可以。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define maxn 220000
#define ls t[p].ch[0]
#define rs t[p].ch[1]
#define pa t[p].f
using namespace std;
int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 - '0' + ch; ch = getchar();}
return x * f;
}

struct node {
int f, ch[2];
int s;
}t[maxn]; int n, m;
bool wh(int p) {return t[pa].ch[1] == p;}
bool Isroot(int p) {return t[pa].ch[0] != p && t[pa].ch[1] != p;}
void update(int p) {t[p].s = t[ls].s + t[rs].s + 1;}

void Rotate(int p) {
int f = pa, g = t[f].f, c = wh(p);
if(!Isroot(f)) t[g].ch[wh(f)] = p; t[p].f = g;
t[f].ch[c] = t[p].ch[c ^ 1]; if(t[f].ch[c]) t[t[f].ch[c]].f = f;
t[p].ch[c ^ 1] = f; t[f].f = p;
update(f);
}

void Splay(int p) {
for(; !Isroot(p); Rotate(p))
if(!Isroot(pa)) Rotate(wh(p) == wh(pa) ? pa : p);
update(p);
}

void Access(int p) {
for(int pre = 0; p; pre = p, p = pa) {
Splay(p);
t[p].ch[1] = pre;
update(p);
}
}

void Link(int p, int g) {
Access(p); Splay(p);
t[ls].f = 0; ls = 0;
pa = g; update(p);
}

void Query(int p) {Access(p); Splay(p); printf("%d\n", t[ls].s + 1);}

int main()
{
n = read();
for(int i = 1;i <= n; ++i) {
int k = read(); t[i].s = 1;
if(i + k <= n) Link(i, i + k);
}
m = read();
for(int i = 1;i <= m; ++i) {
int opt = read();
if(opt == 1) Query(read() + 1);
else {
int x = read() + 1, y = read();
if(x + y > n) Link(x, 0);
else Link(x, x + y);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: