一个线段树加点思维的题目
被窝用splay水过去了Orz
(其实我也不想的,只是正好刚学splay,就看到一个动态插入的题,就。。。就没忍住Orz
用splay写就不用什么思维了,我的思路是给这个队列加上一个虚拟的最后一人来处理刚开始一个人都没有的时候插入的情况
这样写还可以在之后插入的时候无脑插在左边,不用担心没有右边的节点的情况,大概就酱
以及代码如下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define l ch[0]
#define r ch[1]
struct node{
int val,siz;
node * ch[2];
void maintain(){
siz = 1;
if(l) siz+=l->siz;
if(r) siz+=r->siz;
}
};
int siz(node * o){
if(!o)
return 0;
return o->siz;
}
const int maxn = 212345;
node nodes[maxn];
int tot;
void out(node * rot,int d,int k){
if(rot->r)
out(rot->r,d+1,-1);
for(int i=0;i<d;i++)
printf(" ");
if(k==0)
printf("--");
else{
if(k==-1) printf("/");
else printf("\\");
}
printf("%d ( %d )\n",rot->val,rot->siz);
if(rot->l)
out(rot->l,d+1,1);
}
void print(node * root){
out(root,0,0);
}
node * newnode(int x){
node * ret = &nodes[tot++];
ret->val = x;
ret->siz = 1;
ret->l=ret->r=NULL;
return ret;
}
void zg(node* &o,int d){
node * k = o->ch[d];
o->ch[d]=k->ch[d^1];
k->ch[d^1]=o;
o=k;
o->maintain();
o->ch[d^1]->maintain();
}
int splay(node* &rot,int x){
int p = siz(rot->l)+1;
if(p==x)
return 2;
int d = p > x ? 0 : 1;
if(d) x-=p;
int k = splay(rot->ch[d],x);
if(k==2)
return d;
if(k==d) zg(rot,k);
else zg(rot->ch[d],k);
zg(rot,d);
return 2;
}
void fnd(node* &rot,int x){
int k = splay(rot,x);
if(k!=2)
zg(rot,k);
}
void inser(int val,int lo,node* &root){
node * k = newnode(val);
lo++;
if(lo==1){
fnd(root,1);
root->l = k;
root->maintain();
}
else{
fnd(root,lo-1);
fnd(root,lo);
root->l->r = k;
root->l->maintain();
root->maintain();
}
}
int ans[maxn];
int len;
void mid(node *rot){
if(rot->l)
mid(rot->l);
ans[len++]=rot->val;
if(rot->r)
mid(rot->r);
}
int main(){
int n;
while(~scanf("%d",&n)){
tot = 0;
node *rot = newnode(0);
int x,pos;
for(int i=1;i<=n;i++){
scanf("%d %d",&pos,&x);
// print(rot);
inser(x,pos,rot);
}
len = 0;
mid(rot);
for(int i=0;i<n;i++)
printf(i<n-1?"%d ":"%d\n",ans[i]);
}
return 0;
}