[BZOJ3196]二逼平衡树(线段树套splay)
2016-04-29 09:59
417 查看
题目描述
传送门题解
线段树套splay,简单地说就是线段树的每一个节点都吊着一颗splay,表示的是线段树当前节点所表示的区间的点,按权值排序。Q1:线段树常规查询区间,每一次统计小于k的点的个数再相加。
Q2:这个是最麻烦也是最精妙的一问,解决方法是二分答案,每二分到一个答案查询一下这个答案在这个区间内的排名,如果排名等于k+1的话返回它的pre即可。注意这里二分满足条件之后不用查询pre,答案直接为head-1,可以证明head-1一定在序列中。
Q3:相当于线段树的点修改,在splay中删除再插入即可。
Q4:线段树常规查询区间,每一次找区间内比k小的最大的数,然后取max
Q5:类似于Q4,每一次找区间内比k大的最小的数,然后取min
树套树写起来还是比较好写的,但是刚开始姿势不对,尤其是Q2Q4Q5都有比较快的姿势。po主的代码在BZOJ上评测过了,但是tyvjT2组只好弃疗T_T
具体看代码吧,以SegTree为前缀的都是线段树的操作,以Splay为前缀的都是splay的操作,其余的都用比较简单易懂的英文表示w
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int max_n=4e6+5; const int INF=1e9; int n,m,opt,l,r,k,pos,sz,ans,maxn; int seq[max_n],f[max_n],ch[max_n][2],size[max_n],cnt[max_n],key[max_n],root[max_n]; inline int in(){ int x=0,f=1; char ch=getchar(); while (ch>'9'||ch<'0'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } inline void Splay_clear(int x){ f[x]=ch[x][0]=ch[x][1]=size[x]=cnt[x]=key[x]=0; } inline int Splay_get(int x){ return ch[f[x]][1]==x; } inline void Splay_update(int x){ if (x){ size[x]=cnt[x]; if (ch[x][0]) size[x]+=size[ch[x][0]]; if (ch[x][1]) size[x]+=size[ch[x][1]]; } } inline void Splay_rotate(int x){ int old=f[x],oldf=f[old],which=Splay_get(x); ch[old][which]=ch[x][which^1]; f[ch[old][which]]=old; ch[x][which^1]=old; f[old]=x; if (oldf) ch[oldf][ch[oldf][1]==old]=x; f[x]=oldf; Splay_update(old); Splay_update(x); } inline void Splay_splay(int x){ for (int fa;fa=f[x];Splay_rotate(x)) if (f[fa]) Splay_rotate((Splay_get(x)==Splay_get(fa))?fa:x); } inline void Splay_insert(int i,int x){ int now=root[i],fa=0; if (!root[i]){ root[i]=++sz; f[sz]=ch[sz][0]=ch[sz][1]=0; size[sz]=cnt[sz]=1; key[sz]=x; return; } while (1){ if (x==key[now]){ cnt[now]++; Splay_update(fa); Splay_splay(now); root[i]=now; return; } fa=now; now=ch[now][key[now]<x]; if (!now){ ++sz; f[sz]=fa; ch[sz][0]=ch[sz][1]=0; size[sz]=cnt[sz]=1; key[sz]=x; ch[fa][key[fa]<x]=sz; Splay_update(fa); Splay_splay(sz); root[i]=sz; return; } } } inline void Splay_find(int i,int x){ int now=root[i]; while (1){ if (key[now]==x){ Splay_splay(now); root[i]=now; return; } else if (key[now]>x) now=ch[now][0]; else if (key[now]<x) now=ch[now][1]; } } inline int Splay_pre(int i){ int now=ch[root[i]][0]; while (ch[now][1]) now=ch[now][1]; return now; } inline int Splay_next(int i){ int now=ch[root[i]][1]; while (ch[now][0]) now=ch[now][0]; return now; } inline void Splay_del(int i){ int now=root[i]; if (cnt[now]>1){ cnt[now]--; Splay_update(now); return; } if (!ch[now][0]&&!ch[now][1]){ Splay_clear(root[i]); root[i]=0; return; } if (!ch[now][0]){ int oldroot=now; root[i]=ch[oldroot][1]; f[root[i]]=0; Splay_clear(oldroot); return; } if (!ch[now][1]){ int oldroot=now; root[i]=ch[oldroot][0]; f[root[i]]=0; Splay_clear(oldroot); return; } int leftbig=Splay_pre(i),oldroot=root[i]; Splay_splay(leftbig); root[i]=leftbig; ch[root[i]][1]=ch[oldroot][1]; f[ch[oldroot][1]]=root[i]; Splay_clear(oldroot); Splay_update(root[i]); return; } inline int Splay_findrank(int i,int x){ int now=root[i],ans=0; while (1){ if (!now) return ans; if (key[now]==x) return ((ch[now][0])?size[ch[now][0]]:0)+ans; else if (key[now]<x){ ans+=((ch[now][0])?size[ch[now][0]]:0)+cnt[now]; now=ch[now][1]; } else if (key[now]>x) now=ch[now][0]; } } inline int Splay_findpre(int i,int k){ int now=root[i]; while (now){ if (key[now]<k){ if (ans<key[now])ans=key[now]; now=ch[now][1]; } else now=ch[now][0]; } return ans; } inline int Splay_findnext(int i,int k){ int now=root[i]; while (now){ if (key[now]>k){ if (ans>key[now]) ans=key[now]; now=ch[now][0]; } else now=ch[now][1]; } return ans; } inline void SegTree_insert(int now,int l,int r,int x,int v){ int mid=(l+r)>>1; Splay_insert(now,v); if (l==r) return; if (x<=mid) SegTree_insert(now<<1,l,mid,x,v); else SegTree_insert(now<<1|1,mid+1,r,x,v); } inline void SegTree_askrank(int now,int l,int r,int lrange,int rrange,int k){ int mid=(l+r)>>1; if (lrange<=l&&r<=rrange){ ans+=Splay_findrank(now,k); return; } if (lrange<=mid) SegTree_askrank(now<<1,l,mid,lrange,rrange,k); if (mid+1<=rrange) SegTree_askrank(now<<1|1,mid+1,r,lrange,rrange,k); } inline void SegTree_change(int now,int l,int r,int pos,int k){ int mid=(l+r)>>1; Splay_find(now,seq[pos]); Splay_del(now); Splay_insert(now,k); if (l==r) return; if (pos<=mid) SegTree_change(now<<1,l,mid,pos,k); else SegTree_change(now<<1|1,mid+1,r,pos,k); } inline void SegTree_askpre(int now,int l,int r,int lrange,int rrange,int k){ int mid=(l+r)>>1; if (lrange<=l&&r<=rrange){ ans=max(ans,Splay_findpre(now,k)); return; } if (lrange<=mid) SegTree_askpre(now<<1,l,mid,lrange,rrange,k); if (mid+1<=rrange) SegTree_askpre(now<<1|1,mid+1,r,lrange,rrange,k); } inline void SegTree_asknext(int now,int l,int r,int lrange,int rrange,int k){ int mid=(l+r)>>1; if (lrange<=l&&r<=rrange){ ans=min(ans,Splay_findnext(now,k)); return; } if (lrange<=mid) SegTree_asknext(now<<1,l,mid,lrange,rrange,k); if (mid+1<=rrange) SegTree_asknext(now<<1|1,mid+1,r,lrange,rrange,k); } int main(){ n=in(); m=in(); for (int i=1;i<=n;++i) seq[i]=in(),maxn=max(maxn,seq[i]),SegTree_insert(1,1,n,i,seq[i]); for (int i=1;i<=m;++i){ opt=in(); switch(opt){ case 1:{ l=in(); r=in(); k=in(); ans=0; SegTree_askrank(1,1,n,l,r,k); printf("%d\n",ans+1); break; } case 2:{ l=in(); r=in(); k=in(); int head=0,tail=maxn+1,mid; while (head!=tail){ int mid=(head+tail)>>1; ans=0; SegTree_askrank(1,1,n,l,r,mid); if (ans<k) head=mid+1; else tail=mid; } printf("%d\n",head-1); break; } case 3:{ pos=in(); k=in(); SegTree_change(1,1,n,pos,k); seq[pos]=k; maxn=max(maxn,k); break; } case 4:{ l=in(); r=in(); k=in(); ans=0; SegTree_askpre(1,1,n,l,r,k); printf("%d\n",ans); break; } case 5:{ l=in(); r=in(); k=in(); ans=INF; SegTree_asknext(1,1,n,l,r,k); printf("%d\n",ans); break; } } } }
总结
Orz xym 优越的姿势相关文章推荐
- 在switch 分支语句中,default 的位置.对结果有没有影响?
- 九、堆和优先队列---(4)堆排序
- 框架模式 MVC 在Android中的使用
- 【拉勾网职位需求信息爬虫】技能长尾关键词抓取——看看你是否满足企业技能需求
- mysql中datetime比较大小问题
- hmac-md5算法
- Rxjava基础自己总结的有不足欢迎探讨
- linux搜索命令
- njupt Java 实验1
- js中date时间转换yyyy-mm-dd hh:MM:ss等格式字符串
- iOS切图规范
- Arcgis for Js之Graphiclayer扩展详解(饼图)
- "Exception: org.apache.ibatis.builder.xml.IncompleteStatementException: Could not find result map...
- XMLHttpRequest 对象
- 有价值的垂直媒体长什么样
- CSS3基础第二篇(变形,动画)
- 欢迎使用CSDN-markdown编辑器
- 在Android中查看和管理sqlite数据库
- POJ_2914_Minimum_Cut_(Stoer_Wagner)
- 《Linux操作系统分析》之Linux系统的理解及学习Linux内核的心得