bzoj4764 弹飞大爷 LCT
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=4764
题解
如果 \(a_i > 0\) 的话,那么就是 bzoj2002 的原题。直接用 LCT 维护就可以了。
但是现在这个题因为 \(a_i\) 任意,所以不能保证每个点向弹向的点连边一定是一棵树。
但是因为每个点的出边只有一条,所以一定是基环树森林。
考虑如何用 LCT 维护基环树。
首先这个环一定出现在根的位置。所以不妨用一个变量存一下这个根有没有额外的环边。
link 的时候,如果不连通,那么就直接连接。如果联通,那么就记录一下额外边。
cut 的时候,如果 cut 的是额外边那么直接把记录删掉。如果不是,直接 cut。但是这样可能会把根和它的额外边的点分离,这时候额外边就可以转正了。
其实还想到一个做法。
先求出每条边的消失的时间。然后每条边以这个东西为权值用 LCT 维护最大生成树。同时维护这个生成树中有没有环边。
加边的时候就是一般的生成树维护;
删边时候如果不是环边就直接 cut,不用考虑转正的问题了。
时间复杂度 \(O(m\log n)\)。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 200000 + 7;
#define lc c[0]
#define rc c[1]
int n, m;
int a[N], ex[N];
struct Node { int c[2], fa, s; } t[N];
int st[N];
inline bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
inline bool idtfy(int o) { return t[t[o].fa].rc == o; }
inline void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
inline void pushup(int o) { t[o].s = t[t[o].lc].s + t[t[o].rc].s + 1; }
inline void rotate(int o) {
int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
if (!isroot(fa)) t[pa].c[d2] = o; t[o].fa = pa;
connect(o, fa, d1 ^ 1), connect(fa, b, d1);
pushup(fa), pushup(o);
assert(!t[0].lc && !t[0].rc);
}
inline void splay(int o) {
while (!isroot(o)) {
int fa = t[o].fa;
if (isroot(fa)) rotate(o);
else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
else rotate(o), rotate(o);
}
}
inline void access(int o) {
for (int x = 0; o; o = t[x = o].fa)
splay(o), t[o].rc = x, pushup(o);
}
inline int getrt(int o) {
access(o), splay(o);
while (t[o].lc) o = t[o].lc;
return splay(o), o;
}
inline void link(int x, int y) { // x -> y
splay(x);
assert(!t[x].fa);
t[x].fa = y;
}
inline void cut(int x, int y) { // x -> y
access(y), splay(x);
assert(t[x].fa == y);
t[x].fa = 0;
}
inline void work() {
while (m--) {
int opt, x;
read(opt), read(x);
if (opt == 1) {
int rt = getrt(x);
if (ex[rt]) puts("-1");
else access(x), splay(x), printf("%d\n", t[x].s);
} else {
if (x + a[x] <= n && x + a[x] > 0) {
if (x + a[x] == ex[x]) ex[x] = 0;
else {
cut(x, x + a[x]);
int rt = getrt(x + a[x]);
if (ex[rt] && getrt(ex[rt]) != rt) link(rt, ex[rt]), ex[rt] = 0;
}
}
read(a[x]);
if (x + a[x] <= n && x + a[x] > 0) {
if (getrt(x + a[x]) == x) ex[x] = x + a[x];
else link(x, x + a[x]);
}
}
}
}
inline void init() {
read(n), read(m);
for (int i = 1; i <= n; ++i) {
read(a[i]);
if (i + a[i] <= n && i + a[i] > 0) {
int y = i + a[i];
if (getrt(y) == i) ex[i] = y;
else link(i, y);
}
}
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
bzoj4764 弹飞大爷 LCT的更多相关文章
- BZOJ4764弹飞大爷——LCT
题目描述 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值, ...
- 【BZOJ4764】弹飞大爷 LCT
[BZOJ4764]弹飞大爷 Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列 ...
- 【LCT维护基环内向树森林】BZOJ4764 弹飞大爷
4764: 弹飞大爷 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 101 Solved: 52[Submit][Status][Discuss] ...
- 【BZOJ】4764: 弹飞大爷 LCT
[题意]给定n个数字ai,表示大爷落到i处会被弹飞到i+ai处,弹飞到>n或<1处则落地.m次操作,修改一个ai,或询问大爷落到x处经过几次落地(或-1).n,m<=10^5,|ai ...
- bzoj4764: 弹飞大爷
Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小 ...
- BZOJ 4764: 弹飞大爷 LCT
思路并不难,主要是细节需要注意一下. 在 lct 中,删边要写成:f[lson]=0,lson=0 (因为删 x->y 时 y 不一定是左儿子,y 只是 x 的前驱) 然后 f[lson]=ls ...
- bzoj4764: 弹飞大爷 link-cut-tree
题目传送门 这道题啊 调了一个晚上 因为写的是一个有根树和n个基环的写法 所以写得很奇怪..... 最后发现单独处理树的时候不能随意改变S(就是原来的根)不然size会出错.... #include& ...
- BZOJ 4764: 弹飞大爷
4764: 弹飞大爷 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 4 Solved: 4[Submit][Status][Discuss] Des ...
- [BZOJ2002] [Hnoi2010] Bounce 弹飞绵羊 (LCT)
Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...
随机推荐
- leetcode 27. 移除元素(python)
1. 题目描述 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外 ...
- GO开发:etcd用法
etcd是什么? A highly-available key value store for shared configuration and service discovery.是一个键值存储仓库 ...
- Win7上防火墙开放FTP服务以及ping解决方案
1.windows 防火墙开放ftp服务 The following 4 steps will allow both non-secure and SSL FTP traffic through fi ...
- tensorflow学习之tf.truncated_normal和tf.random_noraml的区别
tf版本1.13.1,CPU 最近在tf里新学了一个函数,一查发现和tf.random_normal差不多,于是记录一下.. 1.首先是tf.truncated_normal函数 tf.truncat ...
- MSSQL注入--反弹注入
明明是sql注入的点,却无法进行注入,注射工具拆解的速度异常的缓慢,错误提示信息关闭,无法返回注入的结果,这个时候你便可以尝试使用反弹注入, 反弹注入需要依赖于函数opendatasource的支持, ...
- 安装Git并关联
下载git 打开git bash 生成key将 key绑定到帐号 输入命令 ssh-keygen -t rsa -C 'LoginName' 根据命令生成的地址找到对应文件复制密钥 打开github登 ...
- 20191127 Spring Boot官方文档学习(4.14-4.17)
4.14.使用RestTemplate调用REST服务 如果需要从应用程序调用远程REST服务,则可以使用Spring Framework的RestTemplate类.由于RestTemplate实例 ...
- js for 循环
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 大二 Java上学期总结
一学期的Java学习结束了,这学期对程序语言的理解更深了,首先感谢李津老师的教导,这学期收获挺多的,不像上学期,这学期没有任何缺课表现,希望之后的语言程序学习会更加努力. 突然感觉Java的学习如此之 ...
- [转帖]深入理解 MySQL—锁、事务与并发控制
深入理解 MySQL—锁.事务与并发控制 http://www.itpub.net/2019/04/28/1723/ 跟oracle也类似 其实所有的数据库都有相同的机制.. 学习了机制才能够更好的工 ...