bzoj 2002: 弹飞绵羊 Link-Cut-Tree
题目:
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的情况,你都要输出一个需要的步数,占一行。
题解:
我们将每个坐标视作一个点
对于每一个\(a_i我们将其视为连接\)(i+a_i,i)\(的一条树边.
表示可以从点i到达点\)(i+a_i)\(对于所有的\)(i+a_i) > n$我们令其为n+1
然后对于每一次询问x,即查询以x为根的时候点(n+1)的深度。
又要求支持修改,所以我们大力上LCT即可.
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 200010;
int n;
namespace Splay{
struct Node{
Node *ch[2],*fa;
int siz;
void update(){
siz = ch[0]->siz + ch[1]->siz + 1;
}
}*null;
Node mem[maxn],*it;
inline void init(){
it = mem;null = it++;null->ch[0] = null->ch[1] = null;
null->fa = null;null->siz = 0;
}
inline Node* newNode(){
Node *p = it++;p->ch[0] = p->ch[1] = p->fa = null;
p->siz = 1;return p;
}
inline void rotate(Node *p,Node *x){
int k = p == x->ch[1];
Node *y = p->ch[k^1],*z = x->fa;
if(z->ch[0] == x) z->ch[0] = p;
if(z->ch[1] == x) z->ch[1] = p;
if(y != null) y->fa = x;
p->fa = z;p->ch[k^1] = x;
x->fa = p;x->ch[k] = y;
x->update();p->update();
}
inline bool isroot(Node *p){
return p == null || (p->fa->ch[0] != p && p->fa->ch[1] != p);
}
inline void splay(Node *p){
while(!isroot(p)){
Node *x = p->fa,*y = x->fa;
if(isroot(x)) rotate(p,x);
else if(p == x->ch[0] ^ x == y->ch[0]) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}p->update();
}
}
namespace LCT{
inline void init(){
Splay::init();
for(int i=1;i<=n+1;++i) Splay::newNode();
}
using namespace Splay;
inline void Access(Node *u){
Node *v = null;
while(u != null){
splay(u);u->ch[1] = v;
v = u;u = u->fa;
}
}
inline void link(Node *u,Node *v){
Access(v);splay(v);
v->fa = u;
}
inline void cut(Node *u,Node *v){
Access(u);splay(u);
Access(v);splay(v);
splay(u);u->ch[1] = u->ch[1]->fa = null;
}
inline int query(Node *x){
Access(x);splay(x);
return x->ch[0]->siz;
}
}
int a[maxn];
int main(){
read(n);LCT::init();
for(int i=1;i<=n;++i){
read(a[i]);
LCT::link(Splay::mem+min(i+a[i],n+1),Splay::mem+i);
}
int m;read(m);
while(m--){
int u,v;read(u);
if(u == 1){
read(u); ++ u;
if(u > n) continue;
printf("%d\n",LCT::query(Splay::mem + u));
}else{
read(u);read(v);++ u;
LCT::cut(Splay::mem+min(u+a[u],n+1),Splay::mem+u);
LCT::link(Splay::mem+min(u+v,n+1),Splay::mem+u);
a[u] = v;
}
}
getchar();getchar();
return 0;
}
bzoj 2002: 弹飞绵羊 Link-Cut-Tree的更多相关文章
- [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree)
[BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree) 题面 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一 ...
- BZOJ 2002 弹飞绵羊(分块)
题目:弹飞绵羊 这道题,据说是lct裸题,但是lct那么高级的数据结构,我并不会,所以采取了学长讲过的分块做法,我们对序列分块,可以定义两个数组,其中一个表示从当前位置跳出当前块需要多少步,另一个数组 ...
- [bzoj] 2002 弹飞绵羊 || LCT
原题 简单的LCT练习题. 我们发现对于一个位置x,他只能跳到位置x+k,也就是唯一的父亲去.加入我们将弹飞的绵羊定义为跳到了n+1,那么这就形成了一棵树.而因为要修改k,所以这颗树是动态连边的,那么 ...
- BZOJ 2002 弹飞绵羊
LCT 刚学LCT,对LCT的性质不太熟练,还需要多多练习.. 对每一个点,将其与它能够到达的点连一条虚边.弹出去的话就用n+1这个节点表示. 第一种操作我们需要从LCT的性质入手,问的问题其实就是x ...
- bzoj 2002 弹飞绵羊 lct裸题
上一次用分块过了, 今天换了一种lct(link-cut tree)的写法. 学lct之前要先学过splay. lct 简单的来说就是 一颗树, 然后每次起作用的都是其中的某一条链. 所以每次如果需要 ...
- bzoj 2002 弹飞绵羊 分块
正解lct,然而本蒟蒻并不会.... 分块思路很清晰,处理出每个点弹出所在块所需要的步数及出去后的第一个位置 #include<cstdio> #include<cstring> ...
- 【BZOJ2002】弹飞绵羊(Link-Cut Tree)
[BZOJ2002]弹飞绵羊(Link-Cut Tree) 题面 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lost ...
- 【BZOJ 2002】【Hnoi 2010】弹飞绵羊 分块||Link Cut Tree 两种方法
ShallWe,Yveh,hmy,DaD3zZ,四人吃冰糕从SLYZ超市出来后在马路上一字排开,,,吃完后发现冰糕棍上写着:“向狮子座表白:愿做你的小绵羊”,,, 好吧在这道题里我们要弹飞绵羊,有分块 ...
- bzoj 2002 Bounce 弹飞绵羊
bzoj 2002 Bounce 弹飞绵羊 设一个虚拟节点表示被弹飞,则每个点的后继点是唯一确定的,每个点向它的后继点连边,就形成了一颗树. 询问就是问某个节点到虚拟节点的路径长度,修改就删除原来向后 ...
随机推荐
- poj1061(extendgcd)
看完题目后,题目要求: 设时间为t (x+mt)%L = (y+nt)%L ( x-y + (m-n)*t )= k*L (k是整数,可为负) 然后就是经典的 xa+yb=c 求解x,y的经典题目了. ...
- 【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机
[BZOJ2780][Spoj]8093 Sevenk Love Oimaster Description Oimaster and sevenk love each other. But r ...
- 星球大战starwar(并查集)
1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 5253 Solved: 2395[Submit ...
- Codeforces Round #254 (Div. 2)B. DZY Loves Chemistry
B. DZY Loves Chemistry time limit per test 1 second memory limit per test 256 megabytes input standa ...
- Android Screen Orientation
Ref:Android横竖屏切换小结 Ref:Android游戏开发之横竖屏的切换(二十七)
- activiti基础--0------------------------------生成23张表
1.工作流activiti.cfg.xml配置文件 <beans xmlns="http://www.springframework.org/schema/beans" xm ...
- SVN代码merge
如何merge代码?建议用命令搞merge,客户端图形界面不是很给力.SVN 1.5以上版本,可以使用SVN的自动合并:将主干合并到分支:进入分支目录,执行命令: svn merge http://s ...
- 冒泡排序的三种实现(Java)
冒泡排序是非常好理解的,以从小到大排序为例,每一轮排序就找出未排序序列中最大值放在最后. 设数组的长度为N: (1)比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换. (2)这样 ...
- java并发实现原子操作
来自<java并发编程的艺术>.只是方便自己以后查找. 处理器如何实现原子操作 32位IA-32处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作.首先处理器会自动保证基 ...
- winform窗体取消最大化双击标题最大化
实现目标,固定窗体大小,1.窗体标题去掉最大化按钮2.双击窗体标题也不会最大化,彻底取消最大化 问题,如果设置窗体MaximizeBox和MinimumSize属性,看似问题解决了,单随之而来的问题是 ...