【LCT维护基环内向树森林】BZOJ4764 弹飞大爷

4764: 弹飞大爷

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 101  Solved: 52
[Submit][Status][Discuss]

Description

自从WC退役以来,大爷是越来越懒惰了。为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们

决定齐心合力构造一个下面这样的序列。这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了

第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中ai就是第i个小伙伴的力量值,也

就是序列的第i项。然而,因为大爷太沉了,所以有些小伙伴不能撑到锻(you)炼(xi)结束,所以我们中途会替

换一些小伙伴,也就是改变序列的某些项。而且,因为大爷太沉了,所以有些小伙伴不能把大爷扔向前方,而是会

把大爷往反方向扔,也就是序列中的一些项会是负的(当然,也可能是零喽)。现在机智的大爷通过在空中的观察

,已经知道小伙伴们的所有活动——即初始序列、所有更改操作,他想请你算一算,如果他在某时刻落到了某个位

置,那么他会在几次弹起之后落到小伙伴序列之外(毕竟摔在地上还是蛮疼的)。

Input

第一行为两个整数N和M,代表序列长度和操作次数。

第二行为N个整数,代表初始的小伙伴序列。

接下来有M行,每行代表一个操作。

如果这一行的第一个数是1,代表该操作是一个询问操作,接下来一个数X,代表询问此时大爷从X处,经过几次弹

起会摔在地上。如果永远不会摔在地上,请输出-1。

如果这一行的第一个数是2,代表该操作是一个更改操作,接下来两个数X,Y,代表将序列的第X项改为Y。

N,M <= 200000  |Ai| < N

Output

对于每次询问操作,输出弹起次数或-1。

Sample Input

3 19

1 1 1

1 1

1 2

1 3

2 1 2

1 1

1 2

1 3

2 3 -1

1 1

1 2

1 3

2 2 233

1 1

1 2

1 3

2 2 -233

1 1

1 2

1 3

Sample Output

3

2

1

2

2

1

-1

-1

-1

3

1

2

3

1

2

题解

LCT维护基环内向树森林

具体来说,就是当我们原来维护的无向图变成了一个每个点出度为1的有向图

显然它是可能存在环的,并且更重要的是它不能换根(方向问题)

所以若它是一棵树的话,正常维护LCT

如果它形成了环,我们记一下这个联通块的根到达的点的位置pos[i]

对于Link操作,我们判断一下这条有向边x--->y的端点y在被连接之前的根节点是否已经可以是x

  • 如果是,那么加上这条边之后形成环,我们显然不能把它加上,所以我们令pos[x]=y
  • 如果不是,正常地把x连到y的下面

对于Cut操作,我们要判断一下这条有向边x--->y的端点x形成的环是否正好连到y,即判断pos[x]是否等于y

  • 如果是,那么直接把环去掉,即令pos[x]=0
  • 如果不是,我们先记一下x在联通块中的根节点rt,然后正常地去掉这条边
  • 但是然后我们还要判断一下割断这条边后是否会保留原来的环,如果已经没环,就把记录的边加上,如果环还在,退出

具体看代码吧

代码

//by 减维
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<bitset>
#include<set>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<ctime>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define mpr make_pair
#define maxn 200005
#define inf (1<<30)
#define eps 1e-8
#define pi 3.1415926535897932384626L
using namespace std;

inline int read()
{
    int ret=0;bool fla=0;char ch=getchar();
    while((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘)ch=getchar();
    if(ch==‘-‘){fla=1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){ret=ret*10+ch-‘0‘;ch=getchar();}
    return fla?-ret:ret;
}

int n,m,fa[maxn],son[maxn][2],siz[maxn],rev[maxn],pos[maxn];
int a[maxn];

il bool pdp(int x){return son[fa[x]][1]==x;}
il bool isrt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
il void rever(int x){rev[x]^=1;swap(son[x][0],son[x][1]);}
il void upda(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}

il void pdn(int x)
{
    if(rev[x])
    {
        if(son[x][0]) rever(son[x][0]);
        if(son[x][1]) rever(son[x][1]);
        rev[x]=0;
    }
}

void pd(int x){if(!isrt(x)) pd(fa[x]);pdn(x);}

il void rot(int x)
{
    int f=fa[x],g=fa[f],o=pdp(x);
    if(!isrt(f)) son[g][pdp(f)]=x;fa[x]=g;
    son[f][o]=son[x][!o];fa[son[f][o]]=f;
    son[x][!o]=f;fa[f]=x;
    upda(f),upda(x);
}

il void splay(int x)
{
    pd(x);
    for(;!isrt(x);rot(x))
        if(!isrt(fa[x])) rot(pdp(fa[x])==pdp(x)?fa[x]:x);
}

il void acc(int x)
{
    for(int y=0;x;y=x,x=fa[x])
        splay(x),son[x][1]=y,upda(x);
}

il int find(int x)
{
    acc(x),splay(x);
    while(son[x][0]) pdn(x),x=son[x][0];
    return x;
}

il void link(int x,int y)
{
    if(find(y)==x) pos[x]=y;
    else acc(x),splay(x),fa[x]=y;
}

il void cut(int x,int y)
{
    if(pos[x]==y) pos[x]=0;
    else{
        int t=find(x);
        acc(x),splay(x),fa[son[x][0]]=0,son[x][0]=0,upda(x);
        if(pos[t]&&find(pos[t])!=t) link(t,pos[t]),pos[t]=0;
    }
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i]=read(),siz[i]=1;
    for(int i=1;i<=n;++i)
        if(i+a[i]>=1&&i+a[i]<=n) link(i,a[i]+i);
    for(int i=1,op,x,y;i<=m;++i)
    {
        op=read(),x=read();
        if(op==1){
            acc(x),y=find(x);
            if(pos[y]) puts("-1");
            else splay(x),printf("%d\n",siz[x]);
        }else{
            y=read();
            if(x+a[x]>=1&&a[x]+x<=n) cut(x,a[x]+x);
            if(x+y>=1&&x+y<=n) link(x,x+y);
            a[x]=y;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/rir1715/p/8313181.html

时间: 2024-11-05 19:05:38

【LCT维护基环内向树森林】BZOJ4764 弹飞大爷的相关文章

bzoj4764 弹飞大爷 LCT

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4764 题解 如果 \(a_i > 0\) 的话,那么就是 bzoj2002 的原题.直接用 LCT 维护就可以了. 但是现在这个题因为 \(a_i\) 任意,所以不能保证每个点向弹向的点连边一定是一棵树. 但是因为每个点的出边只有一条,所以一定是基环树森林. 考虑如何用 LCT 维护基环树. 首先这个环一定出现在根的位置.所以不妨用一个变量存一下这个根有没有额外的环边. link 的时候,如

bzoj4764: 弹飞大爷 link-cut-tree

题目传送门 这道题啊 调了一个晚上 因为写的是一个有根树和n个基环的写法 所以写得很奇怪..... 最后发现单独处理树的时候不能随意改变S(就是原来的根)不然size会出错.... #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int M=250007; int read(){ int ans=0,f=1

bzoj4764 弹飞大爷

我是萌萌的传送门 你们搞的这个题目啊,exciting!-- LCT裸题嘛.记得特判一下根节点所连出的边是否会成环就行了,还有删边的时候特判一下是否需要把这条边加回去. 几天不写LCT,结果一写就写出各种脑残错误,我怎么这么菜,233-- 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define isroot(x) ((x)->p==null||((x)->p->ch[

【BZOJ4764】弹飞大爷 LCT

[BZOJ4764]弹飞大爷 Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中ai就是第i个小伙伴的力量值,也就是序列的第i项.然而,因为大爷太沉了,所以有些小伙伴不能撑到锻(you)炼(xi)结束,所以我们中途会替换一些小伙伴,也就是改变序列的

BZOJ 4764: 弹飞大爷

4764: 弹飞大爷 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 4  Solved: 4[Submit][Status][Discuss] Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了 第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中

bzoj3510 首都 LCT 维护子树信息+树的重心

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删去这个点以后剩下的连通块最大的最小的点为重心. 一棵树最多只能有两个相邻的直径: 一棵树的重心到一棵树中所有点的距离和最小.(这个也是题目的条件转化为重心的原因) 两棵树的并的重心在两棵树各自的重心的连线上. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置. 有了这些性质,我们可以发现,

【BZOJ】4764 弹飞大爷

[算法]Link-Cut Tree [题意]一个n个数字组成的序列,a[i]表示移动到i+a[i]处,序列值可动态修改,求从i处开始移动到序列外的最小步数. [题解]将序列视为n个点,外界视为n+1,则每个点有且只有一条边连出去,由该性质可知是一个基环内向森林,问题转化为支持插入删除边并求点(n+1)到点i的距离. 由基环内向森林以及点n+1不能向外出边可知点n+1必然在无环的树上,所以若出现环则输出-1.

【bzoj 4764】弹飞大爷

Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中ai就是第i个小伙伴的力量值,也就是序列的第i项.然而,因为大爷太沉了,所以有些小伙伴不能撑到锻(you)炼(xi)结束,所以我们中途会替换一些小伙伴,也就是改变序列的某些项.而且,因为大爷太沉了,

【bzoj 2002】弹飞绵羊

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