【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 分块/LCT

题目描述

某天,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。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

输出

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

样例输入

4
1 2 1 1
3
1 1
2 1 1
1 1

样例输出

2
3


题解

写这道题时LCT还不会写,于是码了分块。

把n个装置分成√n 个块。设p[i]表示从i开始跳出i所在的块后的第一个位置,超过n则为-1;dis[i]为从i到p[i]的次数。

然后修改只在块内修改,查询只遍历每个块,都只需要√n。

时间复杂度O(n√n)。

数据很弱,不需要优化常数,如果TLE,一定是死循环了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int to[200010] , p[200010] , dis[200010];
inline int read()
{
	int num = 0; char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') num = (num << 3) + (num << 1) + ch - '0' , ch = getchar();
	return num;
}
int main()
{
	int n , i , si , m , opt , x , ans;
	n = read();
	si = (int)sqrt(n);
	for(i = 0 ; i < n ; i ++ )
		to[i] = read() + i;
	for(i = n - 1 ; ~i ; i -- )
	{
		if(to[i] >= n) p[i] = -1 , dis[i] = 1;
		else if(to[i] >= (i / si + 1) * si) p[i] = to[i] , dis[i] = 1;
		else p[i] = p[to[i]] , dis[i] = dis[to[i]] + 1;
	}
	m = read();
	while(m -- )
	{
		opt = read() , x = read();
		if(opt == 1)
		{
			ans = 0;
			for(i = x ; ~i ; i = p[i]) ans += dis[i];
			printf("%d\n" , ans);
		}
		else
		{
			to[x] = read() + x;
			for(i = x ; i >= x / si * si ; i -- )
			{
				if(to[i] >= n) p[i] = -1 , dis[i] = 1;
				else if(to[i] >= (x / si + 1) * si) p[i] = to[i] , dis[i] = 1;
				else p[i] = p[to[i]] , dis[i] = dis[to[i]] + 1;
			}
		}
	}
	return 0;
}

17.05.02 更新LCT做法

建立一颗树,每个节点的父节点是它弹一次到达的点,弹出则为n+1(其实可以直接看作森林,然而第一次写保守起见还是建成一棵树)

于是修改操作就是cut+link,查询就是split。

另:这题其实不适合当模板题。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
int fa[N] , c[2][N] , si[N] , rev[N] , next[N];
inline int read()
{
    int ret = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9') ret = (ret << 3) + (ret << 1) + ch - '0' , ch = getchar();
    return ret;
}
void pushup(int k)
{
    si[k] = si[c[0][k]] + si[c[1][k]] + 1;
}
void pushdown(int k)
{
    if(rev[k])
    {
        int l = c[0][k] , r = c[1][k];
        swap(c[0][l] , c[1][l]) , swap(c[0][r] , c[1][r]);
        rev[l] ^= 1 , rev[r] ^= 1;
        rev[k] = 0;
    }
}
bool isroot(int k)
{
    return c[0][fa[k]] != k && c[1][fa[k]] != k;
}
void update(int k)
{
    if(!isroot(k)) update(fa[k]);
    pushdown(k);
}
void rotate(int x)
{
    int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
    if(!isroot(y)) c[c[1][z] == y][z] = x;
    fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
    pushup(y) , pushup(x);
}
void splay(int x)
{
    update(x);
    while(!isroot(x))
    {
        int y = fa[x] , z = fa[y];
        if(!isroot(y))
        {
            if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x)
{
    int t = 0;
    while(x) splay(x) , c[1][x] = t , pushup(x) , t = x , x = fa[x];
}
void makeroot(int x)
{
    access(x) , splay(x);
    swap(c[0][x] , c[1][x]) , rev[x] ^= 1;
}
void link(int x , int y)
{
    makeroot(x) , fa[x] = y;
}
void cut(int x , int y)
{
    makeroot(x) , access(y) , splay(y) , c[0][y] = fa[x] = 0 , pushup(y);
}
int main()
{
    int n , m , i , opt , x , p;
    n = read();
    for(i = 1 ; i <= n + 1 ; i ++ ) si[i] = 1;
    for(i = 1 ; i <= n ; i ++ ) p = read() , next[i] = min(i + p , n + 1) , link(i , next[i]);
    m = read();
    while(m -- )
    {
        opt = read() , x = read() + 1;
        if(opt == 1) makeroot(n + 1) , access(x) , splay(x) , printf("%d\n" , si[c[0][x]]);
        else p = read() , cut(x , next[x]) , next[x] = min(x + p , n + 1) , link(x , next[x]);
    }
    return 0;
}
posted @ 2017-05-02 21:02  GXZlegend  阅读(251)  评论(0编辑  收藏  举报