P6136 【模板】普通平衡树(数据加强版)(替罪羊树模板)
测试链接
题目背景
本题是 P3369 数据加强版,扩大数据范围并增加了强制在线。
题目的输入、输出和原题略有不同,但需要支持的操作相同。
题目描述
您需要动态地维护一个可重集合 MMM,并且提供以下操作:
- 向 MMM 中插入一个数 xxx。
- 从 MMM 中删除一个数 xxx(若有多个相同的数,应只删除一个)。
- 查询 MMM 中有多少个数比 xxx 小,并且将得到的答案加一。
- 查询如果将 MMM 从小到大排列后,排名位于第 xxx 位的数。
- 查询 MMM 中 xxx 的前驱(前驱定义为小于 xxx,且最大的数)。
- 查询 MMM 中 xxx 的后继(后继定义为大于 xxx,且最小的数)。
本题强制在线,保证所有操作合法(操作 222 保证存在至少一个 xxx,操作 4,5,64,5,64,5,6 保证存在答案)。
输入格式
第一行两个正整数 n,mn,mn,m,表示初始数的个数和操作的个数。
第二行 nnn 个整数 a1,a2,a3,…,ana_1,a_2,a_3,\ldots,a_na1,a2,a3,…,an,表示初始的数。
接下来 mmm 行,每行有两个整数 opt\text{opt}opt 和 x′x'x′,opt\text{opt}opt 表示操作的序号($ 1 \leq \text{opt} \leq 6 ),),),x’$ 表示加密后的操作数。
我们记 last\text{last}last 表示上一次 3,4,5,63,4,5,63,4,5,6 操作的答案,则每次操作的 x′x'x′ 都要异或上 last\text{last}last 才是真实的 xxx。初始 last\text{last}last 为 000。
输出格式
输出一行一个整数,表示所有 3,4,5,63,4,5,63,4,5,6 操作的答案的异或和。
输入输出样例 #1
输入 #1
6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 8
3 13
6 7
1 4
输出 #1
6
说明/提示
样例解释
样例加密前为:
6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 9
3 8
6 1
1 0
::::info[每一个操作的输出]
执行第一个操作前,M={1,1,1,4,4,5}M=\{1,1,1,4,4,5\}M={1,1,1,4,4,5},完成后 M={1,1,4,4,5}M=\{1,1,4,4,5\}M={1,1,4,4,5}。
执行第二个操作后 M={1,1,4,4,5,9}M=\{1,1,4,4,5,9\}M={1,1,4,4,5,9}。
第三个操作查询 MMM 中第 111 小的数字,答案为 111。
第四个操作查询 MMM 中 999 的前驱,答案为 555。
第五个操作查询 MMM 中有多少个数比 888 小,并且将答案加 111,答案为 666。
第六个操作查询 MMM 中 111 的后继,答案为 444。
第七个操作完成后 M={0,1,1,4,4,5,9}M=\{0,1,1,4,4,5,9\}M={0,1,1,4,4,5,9}。
输出 1⊕5⊕6⊕4=61\oplus5\oplus6\oplus4=61⊕5⊕6⊕4=6。
::::
限制与约定
对于 100%100\%100% 的数据,1≤n≤1051\leq n\leq 10^51≤n≤105,1≤m≤1061\leq m\leq 10^61≤m≤106,0≤ai,x<2300\leq a_i,x\lt 2^{30}0≤ai,x<230。
本题输入数据较大,请使用较快的读入方式。
upd 2022.7.22\text{upd 2022.7.22}upd 2022.7.22:新增加 999 组 Hack 数据。
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10;
const double ALPHA = 0.7;
typedef long long ll;
int n,m;
int head=0;
int cnt=0;
int key[N];
int key_cnt[N];
int ls[N];
int rs[N];
int sz[N];
int diff[N];
int collect[N];
int ci;
int top;
int fa;
int side;
int a[N];
int init(int num)
{key[++cnt]=num;ls[cnt] = rs[cnt] =0;key_cnt[cnt] = sz[cnt] = diff[cnt] = 1;return cnt;
}void up(int i)
{sz[i] = sz[ls[i]]+sz[rs[i]]+key_cnt[i];diff[i] = diff[ls[i]]+diff[rs[i]]+(key_cnt[i]>0?1:0);
}void inorder(int i)
{if(i!=0){inorder(ls[i]);if(key_cnt[i]>0)collect[++ci]=i;inorder(rs[i]);}
}int build(int l,int r)
{if(l>r)return 0;int m = (l+r)>>1;int h = collect[m];ls[h] = build(l,m-1);rs[h] = build(m+1,r);up(h);return h;
}void rebuild()
{if(top!=0){ci=0;inorder(top);if(ci>0){if(fa==0)head = build(1,ci);else if(side==1) ls[fa] = build(1,ci);else rs[fa] = build(1,ci);}}
}bool balance(int i)
{return ALPHA*diff[i]>=max(diff[ls[i]],diff[rs[i]]);
}void add(int i,int f,int s,int num)
{if(i==0){if(f==0)head = init(num);else if(s==1) ls[f] = init(num);else rs[f] = init(num);}else {if(key[i]==num)key_cnt[i]++;else if(key[i]>num)add(ls[i],i,1,num);else add(rs[i],i,2,num);}up(i);if(!balance(i)){top = i;fa = f;side = s;}
}void add(int num)
{top = fa = side = 0;add(head,0,0,num);rebuild();
}int small(int i,int num)
{if(i==0)return 0;if(key[i]>=num)return small(ls[i],num);else return sz[ls[i]]+key_cnt[i]+small(rs[i],num);
}int getRank(int num)
{return small(head,num)+1;
}int index(int i,int x)
{if(sz[ls[i]]>=x)return index(ls[i],x);else if(sz[ls[i]]+key_cnt[i]<x)return index(rs[i],x-sz[ls[i]]-key_cnt[i]);return key[i];
}int index(int x)
{return index(head,x);
}int pre(int num)
{int kth = getRank(num);if(kth==1)return INT_MIN;else return index(kth-1);
}int post(int num)
{int kth = getRank(num+1);if(kth==sz[head]+1)return INT_MAX;else return index(kth);
}void remove(int i,int f,int s,int num)
{if(key[i]==num)key_cnt[i]--;else if(key[i]>num)remove(ls[i],i,1,num);else remove(rs[i],i,2,num);up(i);if(!balance(i)){top = i;fa = f;side = s;}
}void remove(int num)
{if(getRank(num)!=getRank(num+1)){top = fa = side = 0;remove(head,0,0,num);rebuild();}
}void solve()
{cin>>n>>m;int ans=0;int lans=0;for(int i=1;i<=n;i++){int x;cin>>x;add(x);}for(int i=1;i<=m;i++){int op,x;cin>>op>>x;x^=lans;if(op==1)add(x);else if(op==2)remove(x);else if(op==3){lans=getRank(x);ans ^= lans;}else if(op==4){lans=index(x);ans^=lans;}else if(op==5){lans=pre(x);ans^=lans;}else if(op==6){lans=post(x);ans^=lans;}}cout<<ans<<endl;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;// cin>>t;while(t--){solve();}return 0;
}