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个装置,每个装置 ...
随机推荐
- loj#6038 「雅礼集训 2017 Day5」远行
分析 代码 #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define ...
- leetcode 回文二叉树
C++最简单的方法,遍历存在vector<int> ivec容器中,然后头尾对应比较 O(n)时间,O(n)空间 /** * Definition for singly-linked li ...
- 现有1~100 共一百个自然数,已随机放入一个有98个元素的数组a[98].要求写出一个尽量简单的方案找出没有被放入数组的那2个数,并在屏幕上打印这2个数
void test7() { try { ]; ]; ]; ; ; int i; ; i < num.Length; i++) { num[i] = i + ; num1[i] = i + ;/ ...
- 【MyBatis】-----初识【MyBatis】
一.核心配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration ...
- Cygwin 技巧
apt-cyg mirror 'https://mirrors.aliyun.com/cygwin/' #设置镜像 windows下安装工具包 inetutils;其中包含telnet等命令; Pyt ...
- centos7:storm集群环境搭建
1.安装storm 下载storm安装包 在线下载 wget http://apache.fayea.com/storm/apache-storm-1.1.1/apache-storm-1.1.1.t ...
- python+selenium切换窗口(获取句柄信息)
current_window_handle:获得当前窗口句柄: window_handles:返回所有窗口的句柄到当前会话: switch_to.window(suoyou[0]) ========= ...
- 实验报告5&第七周课程总结
实验四 类的继承 实验目的 理解抽象类与接口的使用: 了解包的作用,掌握包的设计方法. 实验要求 掌握使用抽象类的方法. 掌握使用系统接口的技术和创建自定义接口的方法. 了解 Java 系统包的结构. ...
- [转帖]Twitter 宣布抛弃 Mesos,全面转向 Kubernetes
Twitter 宣布抛弃 Mesos,全面转向 Kubernetes http://www.itpub.net/2019/05/06/1788/ 事实标准了. 作者 | 阿里云智能高级技术专家 张 ...
- eclipse中经常用到的修改菜单项
1.编写java程序时,书写一个类之后,要调用此类的某个方法时,点个点,此类的所有方法都会自动出现,然后再选择需要的那个方法即可: 2.鼠标放在一个类上面,关于此类的相关描述就会自动加载出来,要修改的 ...