【题意】给定n个数字ai,表示大爷落到i处会被弹飞到i+ai处,弹飞到>n或<1处则落地。m次操作,修改一个ai,或询问大爷落到x处经过几次落地(或-1)。n,m<=10^5,|ai|<=n。

【算法】Link-Cut Tree

【题解】n个点n条出边,构成了神奇的基环内向森林。将落地视为第n+1个点,而第n+1个点没有出边,也就是第n+1个点所在的连通子图是一棵树。

当询问的点所在联通子图是基环内向树时无解,是树时则与第n+1个点的距离就是答案。

因为要资瓷动态删除和加入边,所以考虑用LCT维护。

对于一个环,将环上加入的最后一条边隐藏,标记该环上所有点。

当需要删除时,如果两点间没有连边就删除隐藏边(删除标记也要下传),如果删除的是实边且两点有同一条隐藏边,那么这条隐藏边需要显现。

询问的时候若x和n+1不在同一个连通子图则无解,否则将x作为中心后access(x),路径长度就是size。

【实现】首先需要明确LCT标记传递

1.标记打在splay的根,影响范围有且仅有整棵splay的节点(在程序中规定,标记下传一次后就不再下传)。

2.lct的操作全部自底向上,只要在rotate和access时上传,splay和findroot时下传,就可以保证标记全部传达到位。

还需要注意的是,与模板题不同,特殊的题目会在link和cut时出现本不该有的输入,比如x=y的情况要特判掉。

1.Link(x,y)

如果两点在同一棵树上,那么新加隐藏边,在这棵树的splay根打标记。否则正常操作。

2.Cut(x,y)

将x-y变成主链,如果距离>1(包括x有右儿子的情况!)就删除隐藏边。因为x-y路径其实就是隐藏边所在环,所以可以标记到整个环。

否则删除实边,然后x和y的隐藏边若相同则显现隐藏边——此时x和y是两棵树,要分别变成所在splay的根后打删除隐藏边的标记。

主要是将所有要标记的点变成主链再标记。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int read(){
int s=,t=;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
int t[maxn][],h[maxn],g[maxn],hu[maxn],hv[maxn],sz[maxn],f[maxn],b[maxn],a[maxn],n;
bool isroot(int x){return !x||(t[f[x]][]!=x&&t[f[x]][]!=x);}
void up(int x){sz[x]=sz[t[x][]]+sz[t[x][]]+;}
void down(int x){
if(g[x]){
swap(t[x][],t[x][]);
if(t[x][])g[t[x][]]^=;
if(t[x][])g[t[x][]]^=;
g[x]=;
}
if(h[x]){//
if(t[x][]){h[t[x][]]=;hu[t[x][]]=hu[x];hv[t[x][]]=hv[x];}
if(t[x][]){h[t[x][]]=;hu[t[x][]]=hu[x];hv[t[x][]]=hv[x];}
h[x]=;
}
}
void rotate(int y){
int x=f[y];
int k=y==t[x][];//
t[x][!k]=t[y][k];f[t[y][k]]=x;
if(!isroot(x))t[f[x]][x==t[f[x]][]]=y;f[y]=f[x];f[x]=y;
t[y][k]=x;
up(x);up(y);
}
void splay(int x){
int top=x,tot=;b[]=x;
while(!isroot(top))top=f[top],b[++tot]=top;
for(int i=tot;i>=;i--)down(b[i]);
while(!isroot(x)){
if(isroot(f[x])){rotate(x);break;}
int X=x==t[f[x]][],Y=f[x]==t[f[f[x]]][];
if(X^Y)rotate(x),rotate(x);
else rotate(f[x]),rotate(x);
}
}
void access(int x){
int y=;
while(x){
splay(x);
t[x][]=y;
up(x);
y=x;x=f[x];
}
}
void reserve(int x){access(x);splay(x);g[x]^=;}
int root(int x){access(x);splay(x);while(t[x][])x=t[x][];return x;}
void link(int x,int y){
if(x==y)return;
if(root(x)==root(y)){
reserve(x);access(y);splay(y);
h[y]=;hu[y]=x;hv[y]=y;return;
}
reserve(x);f[x]=y;
}
void cut(int x,int y){
if(x==y)return;//
reserve(x);access(y);splay(y);
if(t[y][]!=x||t[x][]){hu[y]=hv[y]=;h[y]=;return;}//
t[y][]=f[x]=;
if(hu[x]&&hu[x]==hu[y]&&hv[x]==hv[y]){
int X=hu[x],Y=hv[x];
reserve(X);reserve(Y);//
f[X]=Y;
hu[X]=hu[Y]=hv[X]=hv[Y]=;
h[X]=h[Y]=;
}
}
int query(int x){
if(root(x)!=root(n+))return -;
reserve(x);access(n+);splay(x);
return sz[t[x][]];
}
int main(){
n=read();int m=read();
for(int i=;i<=n+;i++)sz[i]=;
for(int i=;i<=n;i++){
a[i]=read()+i;
if(a[i]>n||a[i]<)a[i]=n+;
link(i,a[i]);
}
while(m--){
int k=read(),x=read();
if(k==)printf("%d\n",query(x));else{
int y=read()+x;
cut(x,a[x]);
if(y>n||y<)a[x]=n+;else a[x]=y;
link(x,a[x]);
}
}
return ;
}

【BZOJ】4764: 弹飞大爷 LCT的更多相关文章

  1. BZOJ 4764: 弹飞大爷 LCT

    思路并不难,主要是细节需要注意一下. 在 lct 中,删边要写成:f[lson]=0,lson=0 (因为删 x->y 时 y 不一定是左儿子,y 只是 x 的前驱) 然后 f[lson]=ls ...

  2. BZOJ 4764: 弹飞大爷

    4764: 弹飞大爷 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 4  Solved: 4[Submit][Status][Discuss] Des ...

  3. 【BZOJ4764】弹飞大爷 LCT

    [BZOJ4764]弹飞大爷 Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列 ...

  4. BZOJ4764弹飞大爷——LCT

    题目描述 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值, ...

  5. [bzoj] 2002 弹飞绵羊 || LCT

    原题 简单的LCT练习题. 我们发现对于一个位置x,他只能跳到位置x+k,也就是唯一的父亲去.加入我们将弹飞的绵羊定义为跳到了n+1,那么这就形成了一棵树.而因为要修改k,所以这颗树是动态连边的,那么 ...

  6. bzoj4764 弹飞大爷 LCT

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4764 题解 如果 \(a_i > 0\) 的话,那么就是 bzoj2002 的原题.直接 ...

  7. bzoj 2002 弹飞绵羊 lct裸题

    上一次用分块过了, 今天换了一种lct(link-cut tree)的写法. 学lct之前要先学过splay. lct 简单的来说就是 一颗树, 然后每次起作用的都是其中的某一条链. 所以每次如果需要 ...

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

    4764: 弹飞大爷 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 101  Solved: 52[Submit][Status][Discuss] ...

  9. 【bzoj 4764】弹飞大爷

    Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙 ...

随机推荐

  1. 将 Spring 和 Hibernate 与 WebSphere Application Server 一起使用

    本文摘要 如果您考虑将 Spring 或 Hibernate 与 IBM® WebSphere® Application Server 一起使用,则本文向您阐述了如何配置这些框架,以适用于 WebSp ...

  2. 团队项目利用Msbuild自定义Task实现增量发布

    最近一直在做自动部署工具,主要利用到了Msbuild的自定义Task,通过Task我们可以自定义编译.部署过程减少人工直接干预.Msbuild的详细用法,可以去园子里搜一下,有很多的基础教程,这里就不 ...

  3. influxdb 命令

    写入数据: curl -X POST -d '[{"name":"foo","columns":["val"],&quo ...

  4. 【EF】Entity Framework Core 软删除与查询过滤器

    本文翻译自<Entity Framework Core: Soft Delete using Query Filters>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 注意 ...

  5. 树状数组模板(pascal) 洛谷P3374 【模板】树状数组1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  6. 【bzoj3697】采药人的路径 树的点分治

    题目描述 给出一棵 $n$ 个点的树,每条边的边权为1或0.求有多少点对 $(i,j)$ ,使得:$i$ 到 $j$ 的简单路径上存在点 $k$ (异于 $i$ 和 $j$ ),使得 $i$ 到 $k ...

  7. 【Java】数据库查询的数据直接以指定文件类型下载到本地(弹出下载框)

    欲实现的功能目标:当点击下图的导出数据文件时弹出文件下载框,默认csv格式,用户自定义下载的本地路径 遇到的问题: 1.项目之前做过一次下载,但是是使用了本地文件模板.用输入流读取文件模板,插入数据, ...

  8. Day20-单表中获取表单数据的3种方式

    1. 搭建环境请参考:http://www.cnblogs.com/momo8238/p/7508677.html 2. 创建表结构 models.py from django.db import m ...

  9. Qt 多线程同步与通信

    Qt 多线程同步与通信 1 多线程同步 Qt提供了以下几个类来完成这一点:QMutex.QMutexLocker.QSemphore.QWaitCondition. 当然可能还包含QReadWrite ...

  10. 【刷题】BZOJ 2555 SubString

    Description 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支 ...