zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    
  • 相关阅读:
    归并排序
    数据组合求值
    轨道周期
    类及对象构建
    日期改写
    排列组合去重
    库存更新
    Java性能测试从入门到放弃-详解篇
    Java性能测试从入门到放弃-概述篇
    cocos2d-x安装教程
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6522890.html
Copyright © 2011-2022 走看看