hdu 4699 Editor
题意:对一个数列进行操作,光标位置后面插入一个权值为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 -- ; } } } }