您的位置:首页 > 其它

【bzoj 3595】: [Scoi2014]方伯伯的Oj

2018-07-30 16:23 363 查看
传送门&& 原题解

蒟蒻终于做到一道方伯伯的题了……

调了一个上午一直TLE(发现自己打了好久的splay板子竟然是错的这种丢人事情我就不说了)

很明显,要建两棵树,$T1$维护排名,$T2$维护编号,$T2$表示编号为$x$的点在$T1$中的节点编号

操作一:在$T2$中找到编号,到$T1$算排名,然后更新$T2$

其他操作类似

然后重点讲一下分点操作

因为只有$10^5$个操作,但却有$10^8$个点,所以不可能对每一个点都建树

于是我们考虑一下,让splay的每一个节点代表的不是点,而是一个区间。当需要用到点时,再把这个点从区间中分裂出来

这样可以保证不需要用到的节点不会影响复杂度

关于分点操作具体如何实现,可以参考代码

//minamoto
#include<bits/stdc++.h>
using namespace std;
const int N=330005,INF=0x3f3f3f3f;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
char buf[1<<15],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=0;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*10+num);
(flag)&&(res=-res);
#undef num
return res;
}
char obuf[1<<24],*o=obuf;
void print(int x){
if(x>9) print(x/10);
*o++=x%10+48;
}
map<int,int> f;int n,m,ans;
struct node{
int fa,ch[2];
int sz,l,r;
} e
;
int cnt,root;
void pushup(int x){
e[x].sz=e[e[x].ch[0]].sz+e[e[x].ch[1]].sz+e[x].r-e[x].l+1;
}
void rotate(int x){
int y=e[x].fa,z=e[y].fa;
int op= e[y].ch[1]==x;
e[x].fa=z;
if(z) e[z].ch[e[z].ch[1]==y]=x;
e[y].ch[op]=e[x].ch[op^1],e[e[x].ch[op^1]].fa=y;
e[y].fa=x;e[x].ch[op^1]=y;
pushup(x),pushup(y);
}
void splay(int x,int goal){
while(e[x].fa!=goal){
int y=e[x].fa,z=e[y].fa;
if(z!=goal)
((e[z].ch[0]==y)^(e[y].ch[0]==x))?rotate(x):rotate(y);
rotate(x);
}
pushup(x);
if(goal==0) root=x;
}
int query(int x){
splay(x,0);
return e[x].sz-e[e[x].ch[1]].sz;
}
void pop(int x){
int lower=e[x].ch[0];
int upper=e[x].ch[1];
while(e[lower].ch[1]) lower=e[lower].ch[1];
while(e[upper].ch[0]) upper=e[upper].ch[0];
if(!lower&&!upper) {root=0;return;}
if(!lower){
splay(upper,0);
e[x].fa=e[upper].ch[0]=0;
e[x].sz=1,pushup(upper);
}
else if(!upper){
splay(lower,0);
e[x].fa=e[lower].ch[1]=0;
e[x].sz=1,pushup(lower);
}
else{
splay(lower,0),splay(upper,lower);
e[upper].ch[0]=e[x].fa=0;
e[x].sz=1;
pushup(upper),pushup(lower);
}
}
int getKth(int x){
int now=root;
while(true){
int sum=e[e[now].ch[0]].sz+e[now].r-e[now].l+1;
if(e[e[now].ch[0]].sz>=x) now=e[now].ch[0];
else if(sum>=x){x-=e[e[now].ch[0]].sz;break;}
else x-=sum,now=e[now].ch[1];
}
return e[now].l+x-1;
}
void push_front(int x){
if(!root){root=x;return;}
int fa=root;
while(e[fa].ch[0]) e[fa].sz++,fa=e[fa].ch[0];
e[fa].sz++;
e[fa].ch[0]=x,e[x].fa=fa;
splay(x,0);
}
void push_back(int x){
if(!root){root=x;return;}
int fa=root;
while(e[fa].ch[1]) e[fa].sz++,fa=e[fa].ch[1];
e[fa].sz++;
e[fa].ch[1]=x,e[x].fa=fa;
splay(x,0);
}
void split(int x,int id){
int l=e[x].l,r=e[x].r,ls,rs;
if(l==r) return;
if(l==id){
rs=++cnt;
f[r]=rs,f[id]=x;
e[rs].ch[1]=e[x].ch[1];
e[e[rs].ch[1]].fa=rs;
e[x].ch[1]=rs,e[rs].fa=x;
e[rs].l=l+1,e[rs].r=r;
e[x].r=l;
pushup(rs),pushup(x);
}
else if(r==id){
ls=++cnt;
f[r-1]=ls,f[id]=x;
e[ls].ch[0]=e[x].ch[0];
e[e[ls].ch[0]].fa=ls;
e[x].ch[0]=ls,e[ls].fa=x;
e[ls].l=l,e[ls].r=r-1;
e[x].l=r;
pushup(ls),pushup(x);
}
else{
ls=++cnt,rs=++cnt;
f[id]=x,f[id-1]=ls,f[r]=rs;
e[ls].ch[0]=e[x].ch[0],e[rs].ch[1]=e[x].ch[1];
e[e[ls].ch[0]].fa=ls,e[e[rs].ch[1]].fa=rs;
e[x].ch[0]=ls,e[x].ch[1]=rs,e[ls].fa=x,e[rs].fa=x;
e[x].l=e[x].r=id;
e[ls].l=l,e[ls].r=id-1;
e[rs].l=id+1,e[rs].r=r;
pushup(ls),pushup(rs),pushup(x);
}
splay(x,0);
}
void init(){
root=cnt=1;
e[1].l=1,e[1].r=n,e[1].sz=n;
f
=1;
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),m=read();
init();
while(m--){
int opt=read();
switch(opt){
case 1:{
int oid=read()-ans,nid=read()-ans;
int x=f.lower_bound(oid)->second;
split(x,oid);
ans=query(x);
e[x].l=e[x].r=nid,f[nid]=x;
print(ans),*o++='\n';
break;
}
case 2:{
int id=read()-ans;
int x=f.lower_bound(id)->second;
split(x,id);
ans=query(x);
pop(x);
push_front(x);
print(ans),*o++='\n';
break;
}
case 3:{
int id=read()-ans;
int x=f.lower_bound(id)->second;
split(x,id);
ans=query(x);
pop(x);
push_back(x);
print(ans),*o++='\n';
break;
}
case 4:{
int k=read()-ans;
ans=getKth(k);
print(ans),*o++='\n';
break;
}
}
}
fwrite(obuf,o-obuf,1,stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: