BZOJ 3506 Splay伸展树

题目链接

题意:

一共i次操作,每次操作将[i,第i小数所在位置]翻转,输出n个数字,每次翻转操作前第i小数所在位置

思路:

Splay伸展树维护权值并维护区间最小值和区间最小值所在位置,进行区间查询最小值和翻转区间操作,Splay树完成区间操作是先通过Splay操作将L-1Splay到树根,那么此时树根的右子树里面维护就是[l,n],然后将R+1Splay操作到树根的右子树上,那么此时树根右子树的左子树就是区间[L,R]的所有数了,此时你就可以对这个子树进行你想要的查询与修改

因为选定区间时需要先将L-1和R+1翻转到树根,但是L-1可能为0或者R+1可能为n+1这两个节点不存在,所以我们需要添加两个虚拟节点来防止这种越界的危险

至于最小值的维护和区间翻转的实现就具体看代码吧

另外此题可能会出现相同数字,我们需要提前处理一下

处理代码:

struct node
{
    int val,pos;
    friend bool operator<( const node&a , const node&b )
    {
        if ( a.val==b.val )
            return a.pos<b.pos;
        else
            return a.val<b.val;
    }
}data[maxn];
for ( int i=1 ; i<=n ; i++ )
    scanf ( "%d" , &data[i].val ),data[i].pos = i;
sort ( data+1 , data+n+1 );
for ( int i=1 ; i<=n ; i++ )
    a[data[i].pos+1] = i;

C++代码:

#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
typedef double DB;
typedef long long LL;
typedef complex<double>CD;
const int maxn = 100010;
const int mod = 1000000;
const int inf = 0x3f3f3f3f;
const int INF = 0x7FFFFFFF;

void Mod( int &x ){ x%=mod; }
int Min( int a , int b ){ return a<b?a:b; }
int Max( int a , int b ){ return a>b?a:b; }
int Abs( int x ){ return x>=0?x:-x; }
int Random(){ static int seed = 703; return seed=(int)(seed*48271LL%2147483647); }

int n,root,fa[maxn],sz[maxn],son[maxn][2],val[maxn];
int minx[maxn],minp[maxn],rev[maxn],ans[maxn],s[maxn],a[maxn];

struct node
{
    int val,pos;
    friend bool operator<( const node&a , const node&b )
    {
        if ( a.val==b.val )
            return a.pos<b.pos;
        else
            return a.val<b.val;
    }
}data[maxn];
void Update( int k )
{
    int ls = son[k][0];
    int rs = son[k][1];
    minx[k] = val[k];
    minp[k] = k;
    if ( minx[ls]<minx[k] )
        minx[k] = minx[ls],minp[k] = minp[ls];
    if ( minx[rs]<minx[k] )
        minx[k] = minx[rs],minp[k] = minp[rs];
    sz[k] = sz[ls]+sz[rs]+1;
}
void Pushdown( int k )
{
    int ls = son[k][0];
    int rs = son[k][1];
    rev[k] ^= 1;
    rev[ls]^= 1;
    rev[rs]^= 1;
    swap ( son[k][0] , son[k][1] );
}
void Rotate( int x , int kind )
{
    int y = fa[x];
    int z = fa[y];
    son[y][1-kind] = son[x][kind];
    if ( son[x][kind]!=0 )
        fa[son[x][kind]] = y;
    fa[x] = z;
    if ( z!=0 )
        son[z][son[z][1]==y] = x;
    fa[y] = x,son[x][kind] = y;
    Update( y );
    Update( x );
}
void Splay( int x , int ace )
{
    int top = 0;
    for ( int i=x ; i!=0 ; i=fa[i] )
        s[++top] = i;
    for ( int i=top ; i>=1 ; i-- )
        if ( rev[s[i]] )
            Pushdown( s[i] );
    while ( fa[x]!=ace )
    {
        int y = fa[x];
        int z = fa[y];
        if ( z==ace )
            Rotate( x , son[y][1]!=x );
        else
        {
            if ( son[y][1]==x&&son[z][1]==y )
                Rotate( y , 0 ),Rotate( x , 0 );
            else if ( son[y][1]==x&&son[z][0]==y )
                Rotate( x , 0 ),Rotate( x , 1 );
            else if ( son[y][0]==x&&son[z][0]==y )
                Rotate( y , 1 ),Rotate( x , 1 );
            else
                Rotate( x , 1 ),Rotate( x , 0 );
        }
    }
    if ( ace==0 )
        root = x;
}

void Build( int l , int r , int f )
{
    if ( l>r )
        return;
    if ( l==r )
    {
        int now = l,pre = f;
        fa[now] = pre;
        if ( now<pre )
            son[pre][0] = now;
        else
            son[pre][1] = now;
        val[now] = a[now];
        minx[now] = a[now];
        minp[now] = now;
        sz[now] = 1;
        rev[now] = 0;
        return;
    }
    int mid = (l+r)>>1,now = mid,pre = f;
    Build ( l , mid-1 , mid );
    Build ( mid+1 , r , mid );
    fa[now] = pre;
    val[now] = a[now];
    minx[now] = a[now];
    minp[now] = now;
    Update( now );
    if ( now<pre )
        son[pre][0] = now;
    else
        son[pre][1] = now;
}
int Find( int k , int s )
{
    if ( rev[k] )
        Pushdown( k );
    int ls = son[k][0];
    int rs = son[k][1];
    if ( s==sz[ls]+1 )
        return k;
    else if ( s<=sz[ls] )
        return Find( ls , s );
    else
        return Find( rs , s-sz[ls]-1 );
}

int Query( int l , int r )
{
    int x = Find ( root , l );
    int y = Find ( root , r+2 );
    Splay ( x , 0 );
    Splay ( y , x );
    int z = son[y][0];
    return minp[z];
}
void Reverse( int l , int r )
{
    int x = Find( root , l );
    int y = Find( root , r+2 );
    Splay ( x , 0 );
    Splay ( y , x );
    int z = son[y][0];
    rev[z] ^= 1;
}

int main()
{
    for ( ; scanf ( "%d" , &n )==1 ; )
    {
        a[1] = a[n+2] = minx[0] = inf;
        for ( int i=1 ; i<=n ; i++ )
            scanf ( "%d" , &data[i].val ),data[i].pos = i;
        sort ( data+1 , data+n+1 );
        for ( int i=1 ; i<=n ; i++ )
            a[data[i].pos+1] = i;
        Build ( 1 , n+2 , 0 );
        root = ( n+3 )>>1;
        for ( int i=1 ; i<=n ; i++ )
        {
            int x = Query ( i , n );
            Splay ( x , 0 );
            ans[i] = sz[son[x][0]];
            Reverse( i , ans[i] );
        }
        printf ( "%d" , ans[1] );
        for ( int i=2 ; i<=n ; i++ )
            printf ( " %d" , ans[i] );
        printf ( "\n" );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Game_Acm/article/details/81487351