LCT的板子题
蒟蒻看到很多大佬用分块的方法解决了这道题,但是本蒟蒻不会分块,但我会LCT啊,所以就用LCT解决了这道题。
神奇的思路
对于每一个节点 维护他的size,每一个弹射器 由它即将到达的弹射器向他连边
虚拟一个n+1号节点 进行最后一次弹射,
每次直接查询对应位置的size即可。
也就是
把给出的数据当做森林,即i的父亲是i+k[i],询问的是到根的路径长度+1,可以修改父亲。所以只需要link操作即可,注意把超过n的节点设为0。每次询问先access,然后Splay到根(Splay中要维护size),这样所询问的答案就是节点在Splay上的左子树大小+1。
CODE:
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 200010;
inline int read(){
int x = 0;
int flag = true;
int k = getchar();
while(k != '-' && !isdigit(k))
k = getchar();
if(k == '-'){
k = getchar();
flag = false;
}
while(isdigit(k)){
x = x * 10 + k - '0';
k = getchar();
}
return (flag ? x : -x);
}
struct node{
int father;
int ch[2];
int size;
bool is_root;
}tree[maxn];
int n,m,k[maxn];
void update(int x){
tree[x].size=1;
if(tree[x].ch[0]) tree[x].size += tree[tree[x].ch[0]].size;
if(tree[x].ch[1]) tree[x].size += tree[tree[x].ch[1]].size;
}
inline int getson(int x){
return x == tree[tree[x].father].ch[1];
}
void rotate(int x){
if(tree[x].is_root) return;
int k = getson(x),fa = tree[x].father;
int fafa = tree[fa].father;
tree[fa].ch[k] = tree[x].ch[k^1];
if(tree[x].ch[k^1])
tree[tree[x].ch[k^1]].father = fa;
tree[x].ch[k^1] = fa;
tree[fa].father = x;
tree[x].father = fafa;
if(!tree[fa].is_root)
tree[fafa].ch[fa == tree[fafa].ch[1]] = x;
else {
tree[x].is_root = true;
tree[fa].is_root = false;
}
update(fa);
update(x);
}
void Splay(int x){
for(int y ; !tree[x].is_root;rotate(x)){
if(!tree[y = tree[x].father].is_root){
rotate((getson(x) == getson(y)) ? y : x);
}
}
}
void access(int x){
int y = 0;
while(x){
Splay(x);
tree[tree[x].ch[1]].is_root = true;
tree[tree[x].ch[1] = y].is_root = false;
update(x);
x = tree[y = x].father;
}
}
void link(int u,int v){
if(v > n) v = 0;
access(u);
Splay(u);
tree[tree[u].ch[0]].is_root = true;
tree[tree[u].ch[0]].father = 0;
tree[u].ch[0] = 0;
tree[u].father = v;
update(u);
}
int Query(int x){
access(x);
Splay(x);
return tree[tree[x].ch[0]].size + 1;
}
int main(){
n = read();
for(int i = 1 ; i <= n ; i++){
tree[i].is_root = 1;
tree[i].size = 1;
tree[i].father = 0;
tree[i].ch[0] = 0;
tree[i].ch[1] = 0;
}
for(int i = 1 ; i <= n ; i++){
k[i] = read();
link(i,i + k[i]);
}
m = read();
int xx,x,y;
while(m--){
xx = read();
x = read();
if(xx == 1)
printf("%d
",Query(x+1));
else if(xx == 2){
y = read();
link(x + 1,x + y + 1);
}
}
return 0;
}
另外,LCT的时间复杂度是(O(logn^2)),所以不开氧气优化也能过。
蒟蒻的耗时为652ms。