题目大意
给定一个长度为
n
的序列,第
给定
m
个操作,询问从某一位置弹飞一只绵羊需要的弹射次数或者修改某一个位置的
Data Constraint
n≤200000,m≤100000
题解
显然是一个树模型,绵羊被弹到的点就可以看为当前点的父亲。那么修改操作就可以由LCT的Link和Cut实现,询问就是查询当前点到根的路径长度。
时间复杂度: O(mlog2n)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 200000 + 10
bool Rev[N] ;
int Size[N] , Pre[N] , Son[N][2] ;
int fa[N] , D[N] ;
int n , m ;
bool IsRoot( int x ) { return Son[Pre[x]][0] != x && Son[Pre[x]][1] != x ; }
void Push( int x ) {
if ( !Rev[x] ) return ;
swap( Son[x][0] , Son[x][1] ) ;
Rev[Son[x][0]] ^= 1 ;
Rev[Son[x][1]] ^= 1 ;
Rev[x] = 0 ;
}
void Update( int x ) {
Size[x] = Size[Son[x][0]] + Size[Son[x][1]] + 1 ;
}
void Rotate( int x ) {
int F = Pre[x] , G = Pre[F] ;
int Side = ( Son[F][1] == x ) ;
if ( !IsRoot(F) ) Son[G][Son[G][1] == F] = x ;
Pre[x] = G , Pre[F] = x ;
Son[F][Side] = Son[x][!Side] ;
Pre[Son[x][!Side]] = F ;
Son[x][!Side] = F ;
Update(F) ;
Update(x) ;
}
void Splay( int x ) {
D[D[0] = 1] = x ;
for (int now = x ; !IsRoot(now) ; now = Pre[now] ) D[++D[0]] = Pre[now] ;
for (int i = D[0] ; i >= 1 ; i -- ) Push(D[i]) ;
while ( !IsRoot(x) ) {
int y = Pre[x] , z = Pre[y] ;
if ( !IsRoot(y) ) {
if ( ( Son[y][0] == x ) ^ ( Son[z][0] == y ) ) Rotate(x) ;
else Rotate(y) ;
}
Rotate(x) ;
}
Update(x) ;
}
void Access( int x ) {
int last = 0 ;
while ( x ) {
Splay(x) ;
Son[x][1] = last ;
last = x ;
x = Pre[x] ;
}
}
void MakeRoot( int x ) {
Access(x) ;
Splay(x) ;
Rev[x] ^= 1 ;
}
void Link( int u , int v ) {
MakeRoot(v) ;
Pre[v] = u ;
}
void Cut( int u , int v ) {
MakeRoot(u) ;
Access(v) ;
Splay(v) ;
Son[v][0] = Pre[u] = 0 ;
}
void Query( int x ) {
MakeRoot(n+1) ;
Access(x) ;
Splay(x) ;
printf( "%d\n" , Size[x] - 1 ) ;
}
int main() {
scanf( "%d" , &n ) ;
for (int i = 1 ; i <= n ; i ++ ) {
int k ;
scanf( "%d" , &k ) ;
if ( i + k > n ) Pre[i] = fa[i] = n + 1 ;
else Pre[i] = fa[i] = i + k ;
}
scanf( "%d" , &m ) ;
for (int i = 1 ; i <= m ; i ++ ) {
int op ;
scanf( "%d" , &op ) ;
if ( op == 1 ) {
int x ;
scanf( "%d" , &x ) ;
Query( x + 1 ) ;
} else {
int x , k ;
scanf( "%d%d" , &x , &k ) ;
x ++ ;
Cut( x , fa[x] ) ;
if ( x + k > n ) fa[x] = n + 1 ;
else fa[x] = x + k ;
Link( x , fa[x] ) ;
}
}
return 0 ;
}
以上.