hdu 1890伸展树(splay tree)区间翻转

            一道用伸展树实现区间翻转的题..可能是第一次写翻转,明明是一道水题结果又搞了好久- -题意是给一串数,做n次操作,第i次操作选取区间 [a,b] 翻转,其中a为i,b为当前数组中第i小的数,并且输出翻转前第i小的数所在的位置。思路也比较好想,每个节点记录一个翻转标记flip,一个子节点数size,预先存好数组中第k大的数在原串中位置,建树时的下表就是这个位置数组(这个数组排个序,编个号就能求出来了),我建树的时候图省事,直接按序列从左到右建成了一个链......第i次操作时,把节点p(p=第i大的数对应的位置)伸展到根,然后删掉该节点(因为翻转操作之后,前i个位置已经有序,所以这个节点以后也用不上了,所以可以直接删掉),由于每个节点都存下了子节点数,所以直接输出i+左孩子节点数就ok了。最烦的地方仍然是标记的下传,splay(x,tgt)时,上来先把x的下标下传,之后每次判定旋转方向时,先依次下传pre[pre[x]],pre[x],x三个节点的下标,也就是说每次在判定父节点的父节点,父节点,当前节点的位置关系时,先吧这三个节点的下标都下传了,不然可能判断出来的结果就是错的...

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=100000+100;
int site[maxn];
int pre[maxn];
int ch[maxn][2];
int size[maxn],key[maxn];
int flip[maxn];
int root;
int n;
struct node
{
    int dt,id;
}a[maxn];
bool cmpdt(node p,node q)
{
    if (p.dt!=q.dt) return p.dt<q.dt;
    else return p.id<q.id;
}
bool cmpid(node p,node q)
{
    return p.id<q.id;
}
void build()
{
    root=1;
    for(int i=1; i<=n; i++)
    {
        pre[i]=i-1;
        size[i]=n-i+1;
        ch[i][0]=0;
        if (i==n) ch[i][1]==0;
        else ch[i][1]=i+1;
    }
}

void pushup(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void pushdown(int x)
{
    if (flip[x])
    {
        if (ch[x][0])
        {
            flip[ch[x][0]]=flip[ch[x][0]]^1;
        }
        if (ch[x][1])
        {
            flip[ch[x][1]]=flip[ch[x][1]]^1;
        }
        swap(ch[x][0],ch[x][1]);
        flip[x]=0;
    }
 }
void rotate(int x,int kind)
{
    int y=pre[x];
    pushdown(y);
    pushdown(x);
     ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if (pre[y])
    {
        ch[pre[y]][ch[pre[y]][1]==y]=x;
    }
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    pushup(y);
    pushup(x);
}
void splay(int x,int tgt)
{
    pushdown(x);
    while(pre[x]!=tgt)
    {
        int y=pre[x];
        pushdown(pre[y]);
        pushdown(y);
         pushdown(x);
        if (pre[pre[x]]==tgt)
        {
            rotate(x,ch[pre[x]][0]==x);
        }
        else
        {
            int kind=ch[pre[y]][0]==y;
            if (ch[y][kind]==x)
            {
                rotate(x,kind^1);
                rotate(x,kind);
            }
            else
            {
                rotate(y,kind);
                rotate(x,kind);
            }
        }
    }
    pushup(x);
    if (tgt==0) root=x;
}
int find_max(int x)
{
   int res=x;
   pushdown(res);
   while (ch[res][1])
   {
       res=ch[res][1];
       pushdown(res);
   }
   return res;
}
void del()
{
    if (!ch[root][1])
    {
        root=ch[root][0];
        pre[root]=0;
        return;
    }
    if (!ch[root][0])
    {
        root=ch[root][1];
        pre[root]=0;
        return;
    }
    pushdown(root);
    int r=find_max(ch[root][0]);
    splay(r,root);
    ch[r][1]=ch[root][1];
    pre[ch[root][1]]=r;
    pre[r]=0;
    root=r;
    pushup(root);
}
int m;
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    while(~scanf("%d",&n) && n)
    {
        if (n==1)
        {
            scanf("%d",&m);
            printf("1\n");
            continue;
        }
        memset(ch,0,sizeof ch);
        memset(flip,0,sizeof flip);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i].dt);
            a[i].id=i;
        }
        sort(a+1,a+1+n,cmpdt);
        for(int i=1; i<=n; i++)
        {
            a[i].dt=i;
            site[i]=a[i].id;
        }
       // sort(a+1,a+1+n,cmpid);
        build();
        for (int i=1; i<=n; i++)
        {
            splay(site[i],0);
            if (ch[root][0])
            {
                flip[ch[root][0]]=flip[ch[root][0]]^1;
            }
            printf("%d",size[ch[site[i]][0]]+i);
            if (i!=n) printf(" ");
            del();
        }
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(hdu 1890伸展树(splay tree)区间翻转)