日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ3224普通平衡树

發布時間:2025/3/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ3224普通平衡树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

洛谷題面鏈接
很早就過了,太久沒打了,原本是在noip前用來練emacs的手感的。
noip炸了,就滾回來更博客了(安排的計數任務刷不動,學不會容斥,打發時間。。。)
眾所周知,splay是個好算法,有著優秀的時間復雜度和更加優(巨)秀(大)的常數,而且我們得寫雙旋的splay,否則你在luogu得T飛。
我對平衡樹的理解也不深,也只是會使用而已,淺談啊什么的還是寫不出來,我就分析一下每個操作需要注意的吧。

1.insert(x):

由于x的范圍巨大,你需要用編號表示每個點,每個編號記一個權值

2.delete(x):

分多種情況:
1.只有x一個點,直接刪
2.x只有左兒子,把根定為x的左兒子
3.x只有右兒子,同理
4.左右兒子都有,取前驅/后繼(假設為y)旋到根節點,此時x節點只有右兒子(想一想為什么),然后直接將y的右兒子定為x的右兒子。

3.findx(x):

由于這個詢問,你需要把所有權值相同的點都合并成一個點。

4~6

真沒什么細節了!

splay代碼:

#include<cstdio> int n,size[100001],rt,id,v[100001],ch[100001][2],f[100001],cnt[100001]; void update(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];} void move(int x,int &k) {int fa=f[x],faa=f[fa],tmp=(ch[fa][1]==x);if(fa==k)k=x;else ch[faa][ch[faa][1]==fa]=x;ch[fa][tmp]=ch[x][tmp^1];f[ch[x][tmp^1]]=fa;ch[x][tmp^1]=fa;f[fa]=x;f[x]=faa;update(fa),update(x); } void splay(int x,int &k) {while(x!=k){int y=f[x],z=f[y];if(y!=k){if((ch[z][0]==y)^(ch[y][0]==x))move(y,k);else move(x,k);}move(x,k);} } void add(int x) {if(!rt){size[++id]=1,v[id]=x,rt=id,cnt[id]=1;return ;}int now=rt;while(1){if(x==v[now]){cnt[now]++;update(now);splay(now,rt);return ;}else if(x<v[now]){if(!ch[now][0]){v[++id]=x;ch[now][0]=id;size[id]=1;cnt[id]=1;f[id]=now;update(now);break;}now=ch[now][0];}else {if(!ch[now][1]){v[++id]=x;ch[now][1]=id;size[id]=1;cnt[id]=1;f[id]=now;update(now);break;}now=ch[now][1];}}splay(id,rt); } int findS(int k,int x) {if(v[k]==x)return k;if(v[k]>x)return findS(ch[k][0],x);if(v[k]<x)return findS(ch[k][1],x); } int pre() {int x=ch[rt][0];while(ch[x][1])x=ch[x][1];return x; } int nxt() {int x=ch[rt][1];while(ch[x][0])x=ch[x][0];return x; } int findx(int k,int x) {if(!k)return 1;if(v[k]>x)return findx(ch[k][0],x);if(v[k]<x)return size[ch[k][0]]+cnt[k]+findx(ch[k][1],x);if(v[k]==x){int d=size[ch[k][0]];splay(k,rt);return d+1;} } void del(int x) {int now=findS(rt,x);splay(now,rt);if(cnt[now]>1){cnt[now]--;return ;}if(!ch[now][0]&&!ch[now][1]){size[now]=cnt[now]=v[now]=0;rt=0;return ;}if(ch[now][0]&&!ch[now][1]){int y=ch[now][0];ch[now][0]=f[y]=v[now]=cnt[now]=size[now]=0;rt=y;return ;}if(!ch[now][0]&&ch[now][1]){int y=ch[now][1];ch[now][1]=f[y]=v[now]=cnt[now]=size[now]=0;rt=y;return ;}int y=pre(),z=ch[now][1];splay(y,rt);f[z]=y;ch[y][1]=z;update(y); } int find(int k,int x) {if(x<=size[ch[k][0]])return find(ch[k][0],x);if(x>size[ch[k][0]]&&x<=size[ch[k][0]]+cnt[k])return v[k];return find(ch[k][1],x-size[ch[k][0]]-cnt[k]); } int main() {scanf("%d",&n);for(int i=1,op,x,y;i<=n;i++){scanf("%d",&op);if(op==1)scanf("%d",&x),add(x);if(op==2)scanf("%d",&x),del(x);if(op==3)scanf("%d",&x),printf("%d\n",findx(rt,x));if(op==4)scanf("%d",&x),printf("%d\n",find(rt,x));if(op==5)scanf("%d",&x),add(x),printf("%d\n",v[pre()]),del(x);if(op==6)scanf("%d",&x),add(x),printf("%d\n",v[nxt()]),del(x);} }

要知道線段樹也能寫這個題,權值線段樹就好啦
先離散化,對于每個區間記一下該區間內有多少個數就行了,然后所有操作都可以支持了
代碼:

#include<cstdio> #include<algorithm> #include<map> using namespace std; #define mid ((s[x].l+s[x].r)>>1) map<int,int>mp; int n,w[100001],a[100001],b[100001],q[100001],tot,ans1,ans2,ans3; struct oo{int l,r,v,mx,mn;}s[400001]; void build(int x,int l,int r) {s[x].l=l,s[x].r=r,s[x].mn=1e9;if(l==r)return ;build(x<<1,l,mid),build(x<<1|1,mid+1,r); } void update(int x) {s[x].v=s[x<<1].v+s[x<<1|1].v;s[x].mx=max(s[x<<1].mx,s[x<<1|1].mx);s[x].mn=min(s[x<<1].mn,s[x<<1|1].mn); } void change(int x,int l,int v) {if(s[x].l==s[x].r){s[x].v+=v;if(s[x].v)s[x].mx=s[x].mn=l;else s[x].mx=0,s[x].mn=1e9;return ;}if(l<=mid)change(x<<1,l,v);else change(x<<1|1,l,v);update(x); } void get(int x,int l,int r) {if(l>r)return ;if(l<=s[x].l&&r>=s[x].r){ans1+=s[x].v,ans2=max(ans2,s[x].mx),ans3=min(ans3,s[x].mn);return ;}if(l<=mid)get(x<<1,l,r);if(r>mid)get(x<<1|1,l,r); } int ask(int x,int l) {if(s[x].l==s[x].r)return s[x].l;if(l<=s[x<<1].v)return ask(x<<1,l);else return ask(x<<1|1,l-s[x<<1].v); } int main() {scanf("%d",&n);int now=0;for(int i=1;i<=n;i++){scanf("%d%d",&a[i],&b[i]);if(a[i]!=4)w[++now]=b[i];}sort(w+1,w+now+1);for(int i=1;i<=now;i++)if(!mp[w[i]])mp[w[i]]=++tot,q[tot]=w[i];for(int i=1;i<=n;i++)if(a[i]!=4)b[i]=mp[b[i]];build(1,1,tot);for(int i=1;i<=n;i++){if(a[i]==1)change(1,b[i],1);if(a[i]==2)change(1,b[i],-1);if(a[i]==3)ans1=ans2=0,ans3=1e9,get(1,1,b[i]-1),printf("%d\n",ans1+1);if(a[i]==4)printf("%d\n",q[ask(1,b[i])]);if(a[i]==5)ans1=ans2=0,ans3=1e9,get(1,1,b[i]-1),printf("%d\n",q[ans2]);if(a[i]==6)ans1=ans2=0,ans3=1e9,get(1,b[i]+1,tot),printf("%d\n",q[ans3]);} }

轉載于:https://www.cnblogs.com/lcxer/p/10003445.html

總結

以上是生活随笔為你收集整理的BZOJ3224普通平衡树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。