一道用伸展树实现区间翻转的题..可能是第一次写翻转,明明是一道水题结果又搞了好久- -题意是给一串数,做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;
}