代码用时:2h
感觉代码难度很低啊为什么我还是花了很长时间。。
思维比较简单,只要把三种操作想清楚了就差不多了。
比较自然的想法应该是Splay,但线段树实现复杂度和常数都更优。
线段树做法网上好像只找到一个(而且没有标记永久化的代码并不是很优美常数也稍大)
这里有一个自认为比较优的做法。
(本题线段树做法的思想还是有点巧妙的,利用了题目只单旋最值的设定)
12140KB,1108ms
#include<set>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; template<typename T>inline void rd(T &x){
int t; char ch;
for (t=; !isdigit(ch=getchar()); t=(ch=='-'));
for (x=ch-''; isdigit(ch=getchar()); x=x*+ch-'');
if (t) x=-x;
} const int N=;
int m,tot,d,rt,D[N<<],rs[N],ls[N],fa[N],a[N],b[N],op[N][];
set<int>S;
set<int>::iterator it,sub,pro; void mdf(int x,int L,int R,int l,int r,int k){
if (L==l && R==r){ D[x]+=k; return; }
int mid=(L+R)>>;
if (r<=mid) mdf(x<<,L,mid,l,r,k);
else if (l>mid) mdf((x<<)|,mid+,R,l,r,k);
else mdf(x<<,L,mid,l,mid,k),mdf((x<<)|,mid+,R,mid+,r,k);
} int que(int x,int L,int R,int k){
if (L==R) return D[x];
int mid=(L+R)>>;
if (k<=mid) return D[x]+que(x<<,L,mid,k);
else return D[x]+que((x<<)|,mid+,R,k);
} int main(){
freopen("bzoj4825.in","r",stdin);
freopen("bzoj4825.out","w",stdout);
rd(m);
rep(i,,m){
rd(op[i][]); if (op[i][]==) rd(op[i][]);
if (op[i][]==) b[++tot]=op[i][];
}
sort(b+,b+tot+); tot=unique(b+,b+tot+)-b-;
rep(i,,m) if (op[i][]==) a[i]=lower_bound(b+,b+tot+,op[i][])-b;
rep(i,,m){
if (op[i][]==){
if (S.empty()) rt=a[i],d=;
else{
it=S.upper_bound(a[i]),sub=it;
if (sub==S.begin()) ls[*sub]=a[i],fa[a[i]]=*sub,d=que(,,tot,*sub)+;
else{
pro=--it;
if (sub==S.end()) rs[*pro]=a[i],fa[a[i]]=*pro,d=que(,,tot,*pro)+;
else if (que(,,tot,*sub)<que(,,tot,*pro))
rs[*pro]=a[i],fa[a[i]]=*pro,d=que(,,tot,*pro)+;
else ls[*sub]=a[i],fa[a[i]]=*sub,d=que(,,tot,*sub)+;
}
}
printf("%d\n",d); mdf(,,tot,a[i],a[i],d-que(,,tot,a[i]));
S.insert(a[i]);
}
if (op[i][]== || op[i][]==){
it=S.begin(); d=que(,,tot,*it); printf("%d\n",d);
if ((*it)!=rt){
mdf(,,tot,,tot,); mdf(,,tot,*it,*it,-d);
int t=fa[*it]; ls[t]=fa[*it]=;
if (rs[*it]){
mdf(,,tot,(*it)+,t-,-);
fa[rs[*it]]=t; ls[t]=rs[*it];
}
rs[*it]=rt; fa[rt]=*it; rt=*it;
}
if (op[i][]==) rt=rs[*it],rs[*it]=fa[rt]=,mdf(,,tot,,tot,-),S.erase(*it);
}
if (op[i][]== || op[i][]==){
it=S.end(); it--; d=que(,,tot,*it); printf("%d\n",d);
if ((*it)!=rt){
mdf(,,tot,,tot,); mdf(,,tot,*it,*it,-d);
int t=fa[*it]; rs[t]=fa[*it]=;
if (ls[*it]){
mdf(,,tot,t+,(*it)-,-);
fa[ls[*it]]=t; rs[t]=ls[*it];
}
ls[*it]=rt; fa[rt]=*it; rt=*it;
}
if (op[i][]==) rt=ls[*it],ls[*it]=fa[rt]=,mdf(,,tot,,tot,-),S.erase(*it);
}
}
return ;
}
惊了,splay跑的比线段树还快。
5752KB,900ms
代码用时:1h
一开始想自己写出来,思路并不复杂但代码很繁琐(模板占了大部分但想敲对并不容易)。
看了网上的代码抄了一份下来竟然1A,可能是我抄代码的经历中最顺利的一次吧。
但抄来的代码终究不是自己的,要勇于写这种代码稍长的题目,后面还会有比这长的多的题!
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ls c[x][0]
#define rs c[x][1]
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; template<typename T>inline void rd(T &x){
int t; char ch;
for (t=; !isdigit(ch=getchar()); t=(ch=='-'));
for (x=ch-''; isdigit(ch=getchar()); x=x*+ch-'');
if (t) x=-x;
} const int inf=,N=;
int n,cnt,rt,Q,fa[N],v[N],sz[N],c[N][],s[N],dep[N],mn[N]; void push(int x){
v[ls]+=v[x]; dep[ls]+=v[x]; mn[ls]+=v[x];
v[rs]+=v[x]; dep[rs]+=v[x]; mn[rs]+=v[x];
v[x]=;
} void upd(int x){
sz[x]=sz[ls]+sz[rs]+; mn[x]=dep[x];
if (ls) mn[x]=min(mn[x],mn[ls]);
if (rs) mn[x]=min(mn[x],mn[rs]);
} void rot(int &rt,int x){
int y=fa[x],z=fa[y],w=(c[y][]==x);
if (y==rt) rt=x; else c[z][c[z][]==y]=x;
fa[x]=z; fa[y]=x; fa[c[x][w^]]=y;
c[y][w]=c[x][w^]; c[x][w^]=y; upd(y);
} void splay(int &rt,int x){
while (x!=rt) {
int y=fa[x],z=fa[y];
if (y!=rt){
if ((c[z][]==y)^(c[y][]==x)) rot(rt,x); else rot(rt,y);
}
rot(rt,x);
}
upd(x);
} void ins(int &x,int S,int d,int lst){
if (!x){
x=++cnt, s[cnt]=S; dep[cnt]=mn[cnt]=d;
sz[cnt]=; fa[cnt]=lst; return;
}
ins(c[x][S>s[x]],S,d,x); upd(x);
} int getpre(int x,int S){
if (!x) return ;
if (v[x]) push(x);
if (s[x]>S) return getpre(c[x][],S);
Q=getpre(c[x][],S);
if (Q) return Q; else return x;
} int getnxt(int x,int S){
if (!x) return ;
if (v[x]) push(x);
if (s[x]<S) return getnxt(rs,S);
Q=getnxt(ls,S);
if (Q) return Q; else return x;
} int find(int x,int k){
if (v[x]) push(x);
if (sz[ls]+==k) return x;
if (sz[ls]+<k) return find(rs,k-sz[ls]-);
return find(ls,k);
} int getl(int x,int d){
if (!x) return ;
if (v[x]) push(x);
if (min(mn[ls],dep[x])>=d) return getl(rs,d)+sz[ls]+;
else return getl(ls,d);
} int getr(int x,int d){
if (!x) return ;
if (v[x]) push(x);
if (min(mn[rs],dep[x])>=d) return getr(ls,d)+sz[rs]+;
else return getr(rs,d);
} int split(int l,int r){
int t1=find(rt,l-),t2=find(rt,r+);
splay(rt,t1); splay(c[rt][],t2); return c[c[rt][]][];
} void mdf(int l,int r,int ad){
int y=split(l,r); v[y]+=ad; mn[y]+=ad; dep[y]+=ad;
} void change(int x,int S){
if (v[x]) push(x);
if (s[x]==S) dep[x]=; else change(c[x][S>s[x]],S);
upd(x);
} int main(){
freopen("bzoj4825.in","r",stdin);
freopen("bzoj4825.out","w",stdout);
rd(n); ins(rt,-inf,inf,); ins(rt,inf,inf,); mn[]=inf;
rep(i,,n){
int op,x; rd(op);
if (op==){
rd(x); int t1=getpre(rt,x),t2=getnxt(rt,x);
int D=max(t1> ? dep[t1] : ,t2> ? dep[t2] : )+;
ins(rt,x,D,); splay(rt,cnt); printf("%d\n",D);
}
if (!(op&)){
int x=find(rt,),y=min(getl(rt,dep[x]),sz[rt]-)-;
printf("%d\n",dep[x]); mdf(,sz[rt]-,);
if (y>) mdf(,y+,-);
change(rt,s[x]);
}
if ((op&)&&(op>)){
int x=find(rt,sz[rt]-),y=min(getr(rt,dep[x]),sz[rt]-)-;
printf("%d\n",dep[x]); mdf(,sz[rt]-,);
if (y>) mdf(sz[rt]-y,sz[rt]-,-);
change(rt,s[x]);
}
if (op>=){
if (op==) splay(rt,find(rt,));
else splay(rt,find(rt,sz[rt]-));
int l=(op==),r=l^,y=c[rt][l];
c[y][r]=c[rt][r]; fa[y]=; fa[c[rt][r]]=y; rt=y;
v[rt]-=; upd(rt);
}
}
return ;
}