题意:对一个数列进行操作,光标位置后面插入一个权值为x的数,删除光标前的那个数,光标左移一位,光标右移一位,求到k位置的最大的前缀和。。
解题思路:标乘是用了栈进行维护。。我这智商比较捉急啊,用了splay。节点下要记录的是该几点所掌控的子树的前缀最大值是多少,那么要维护这个最大值,就需要一个辅助变量,sum[rt]表示rt节点所掌控的子树的所有数的和,怎么维护前缀最大,看下我的push_up ()函数就知道了,还是很好理解的。左右移,插入,删除都是很常见的splay的操作了,不解释这个了。然后就是询问,询问的时候我们只要把k大的所在的节点转到根,那么根的左儿子所保存的那个最大前缀的信息,自然就是1-(k-1)的所有前缀和里面最大的了,再用左儿子的sum+val[rt]去比较,得出的较大的那个就是答案了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ;
const int maxn = 1000011 ;
int son[2][maxn] , fa[maxn] , size[maxn] ;
int val[maxn] , sum[maxn] , mm[maxn] ;
int tot ;
void push_up ( int x ) {
size[x] = 1 ;
sum[x] = val[x] ;
int ls = son[0][x] , rs = son[1][x] ;
if ( son[0][x] ) size[x] += size[son[0][x]] , sum[x] += sum[son[0][x]] ;
if ( son[1][x] ) size[x] += size[son[1][x]] , sum[x] += sum[son[1][x]] ;
if ( ls ) {
mm[x] = max ( mm[ls] , sum[ls] + val[x] ) ;
if ( rs ) mm[x] = max ( mm[x] , sum[ls] + val[x] + mm[rs] ) ;
}
else {
mm[x] = val[x] ;
if ( rs ) mm[x] += mm[rs] > 0 ? mm[rs] : 0 ;
}
}
void rot ( int x , int c ) {
int y = fa[x] , z = fa[y] ;
son[!c][y] = son[c][x] ;
if ( son[c][x] ) fa[son[c][x]] = y ;
fa[x] = z ;
if ( z ) {
if ( y == son[0][z] ) son[0][z] = x ;
else son[1][z] = x ;
}
son[c][x] = y , fa[y] = x ;
push_up ( y ) ;
}
void splay ( int x , int to ) {
while ( fa[x] != to ) {
if ( fa[fa[x]] == to ) rot ( x , x == son[0][fa[x]] ) ;
else {
int y = fa[x] , z = fa[y] ;
if ( x == son[0][y] ) {
if ( y == son[0][z] ) rot ( y , 1 ) , rot ( x , 1 ) ;
else rot ( x , 1 ) , rot ( x , 0 ) ;
}
else {
if ( y == son[1][z] ) rot ( y , 0 ) , rot ( x , 0 ) ;
else rot ( x , 0 ) , rot ( x , 1 ) ;
}
}
}
push_up ( x ) ;
}
int join ( int r1 , int r2 , int rt ) {//合并以x为根的左右子树
if ( !r1 ) {
if ( !r2 ) return 0 ;
fa[r2] = 0 ;
return r2 ;
}
int x = r1 ;
while ( son[1][x] ) x = son[1][x] ;
splay ( x , rt ) ;
son[1][x] = r2 ;
if ( r2 ) fa[r2] = x ;
fa[x] = 0 ;
push_up ( x ) ;
return x ;
}
int new_node ( int v ) {
size[++tot] = 1 ;
val[tot] = v ;
son[0][tot] = son[1][tot] = fa[tot] = 0 ;
return tot ;
}
int find ( int v , int rt ) {
int cnt = 0 ;
if ( son[0][rt] ) cnt += size[son[0][rt]] ;
if ( cnt + 1 == v ) return rt ;
if ( cnt >= v ) return find ( v , son[0][rt] ) ;
return find ( v - cnt - 1 , son[1][rt] ) ;
}
int main () {
int q , a , b , n ;
char op[111] ;
while ( scanf ( "%d" , &q )!= EOF ) {
int pos = 0 , rt = 0 ;
tot = 0 ;
while ( q -- ) {
scanf ( "%s" , op ) ;
n = size[rt] ;
if ( op[0] == 'Q' ) {
scanf ( "%d" , &a ) ;
int temp = find ( a , rt ) ;
splay ( temp , 0 ) ;
rt = temp ;
temp = son[0][rt] ;
// printf ( "temp = %d , mm = %d, sum = %d , val = %d\n" , temp , mm[temp] , sum[temp] , val[rt] ) ;
int ans ;
if ( temp )
ans = max ( mm[temp] , sum[temp] + val[rt] ) ;
else ans = val[rt] ;
printf ( "%d\n" , ans ) ;
}
else if ( op[0] == 'L' ) pos -= ( pos != 0 ) ;
else if ( op[0] == 'R' ) pos += ( pos != n ) ;
else if ( op[0] == 'I' ) {
scanf ( "%d" , &a ) ;
int temp = new_node ( a ) ;
if ( pos == 0 ) {
son[1][temp] = rt ;
if ( son[1][temp] ) fa[son[1][temp]] = temp ;
rt = temp ;
push_up ( rt ) ;
}
else {
int fuck = find ( pos , rt ) ;
splay ( fuck , 0 ) ;
rt = fuck ;
son[1][temp] = son[1][rt] ;
if ( son[1][temp] ) fa[son[1][temp]] = temp ;
fa[temp] = rt , son[1][rt] = temp ;
push_up ( temp ) ;
push_up ( rt ) ;
}
pos ++ ;
}
else {
int fuck = find ( pos , rt ) ;
splay ( fuck , 0 ) ;
rt = fuck ;
rt = join ( son[0][rt] , son[1][rt] , rt ) ;
pos -- ;
}
}
}
}