https://www.luogu.org/problemnew/solution/P3165
预处理
我们会发现一个问题:高度是无序的,而splay中要求有序,否则kth不能正确求解。
不需要求高度,只要求位置。
所以,用结构体存入 高度 与 下标,按高度排序,然后就可以把高度丢一边了(一波sao操作)。
记得头尾添加两个节点。。。
建树
正常 nlogn 可能会被卡常,所以,类似于线段树的建树,分此节点与左右儿子节点。
区间第k大
正常kth
区间翻转
首先,需要把所求的节点(即排序前下标为id的节点) splay 到 root 。
那么答案就是root左孩子的节点个数(因为有哨兵节点,所以+1-1抵消),记为s。
然后,取出 [i+1 , s+1] 这段区间,即:
将i节点 splay 到根,s+2节点 splay 到i的右节点。
再将s+2的左孩子打上翻转标记即可。
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
#define MAX 999999999//最值
using namespace std;
int n,size=1,root=0;
struct node {
int x,id;
} b[MAXN];
namespace splay {
struct Splay {
int f,s,flag,son[2];
int v;
} a[MAXN];
inline void clean(int rt) { //清空节点
a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].flag=a[rt].v=0;
}
inline void pushup(int rt) { //上传
if(!rt)return;
a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
}
inline void pushdown(int rt) { //标记下传
if(!rt||!a[rt].flag)return;//记得这句
a[a[rt].son[0]].flag^=1;
a[a[rt].son[1]].flag^=1;
a[rt].flag^=1;
swap(a[rt].son[0],a[rt].son[1]);
}
inline void turn(int rt,int k) { //旋转
int x=a[rt].f,y=a[x].f;
a[x].son[k^1]=a[rt].son[k];
if(a[rt].son[k])a[a[rt].son[k]].f=x;
a[rt].f=y;
if(y)a[y].son[a[y].son[1]==x]=rt;
a[x].f=rt;
a[rt].son[k]=x;
pushup(x);
pushup(rt);
}
void splay(int rt,int ancestry) { //伸展
while(a[rt].f!=ancestry) {
int x=a[rt].f,y=a[x].f;
pushdown(y);
pushdown(x);
pushdown(rt);//每次都要下传
if(y==ancestry)turn(rt,a[x].son[0]==rt);
else {
int k=a[y].son[0]==x?1:0;
if(a[x].son[k]==rt) {
turn(rt,k^1);
turn(rt,k);
} else {
turn(x,k);
turn(rt,k);
}
}
}
if(ancestry==0)root=rt;
}
inline int newnode(int x) { //建立新节点
int rt=size++;
clean(rt);
a[rt].v=x;
a[rt].s=1;
return rt;
}
int buildtree(int l,int r) { //建树
if(l>r)return 0;
int mid=l+r>>1,lson=0,rson=0;
lson=buildtree(l,mid-1);
int rt=newnode(b[mid].x);
rson=buildtree(mid+1,r);
a[rt].son[0]=lson;
a[rt].son[1]=rson;
if(lson)a[lson].f=rt;
if(rson)a[rson].f=rt;
pushup(rt);//一定要有这句!
return rt;
}
int kth(int rt,int k) { //第k大值
if(a[rt].s<k)return 0;
while(1) {
pushdown(rt);//下传
int y=a[rt].son[0];
if(k>a[y].s+1) {
k-=a[y].s+1;
rt=a[rt].son[1];
} else if(k<=a[y].s)rt=y;
else return rt;
}
}
inline void reverge(int i) { //区间翻转
splay(b[i].id+1,0);//记得加1(有哨兵节点)
int s=a[a[root].son[0]].s;
printf("%d ",s);
int front=kth(root,i),next=kth(root,s+2);
splay(front,0);
splay(next,front);
a[a[next].son[0]].flag^=1;//打上标记
}
}
inline int read() {
int date=0,w=1;
char c=0;
while(c<'0'||c>'9') {
if(c=='-')w=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
date=date*10+c-'0';
c=getchar();
}
return date*w;
}
bool cmp(const node &x,const node &y) {
if(x.x==y.x)return x.id<y.id;
return x.x<y.x;
}
void init() { //预处理+读入+工作
n=read();
for(int i=1; i<=n; i++) {
b[i].x=read();
b[i].id=i;
}
b[0].x=-MAX;
b[0].id=1;
b[n+1].x=MAX;
b[n+1].id=n+1;//两个哨兵节点
sort(b+1,b+n+1,cmp);
root=splay::buildtree(0,n+1);
for(int i=1; i<=n-1; i++)splay::reverge(i);
printf("%d\n",n);//最后一个一定是 n
}
int main() {
init();
return 0;
}
来源:https://www.cnblogs.com/shandongs1/p/9007019.html