板子集合
放一块方便复习,以及一些懒得写博客的新学知识点
tarjan
点击查看代码
//缩点
void tarjan(int u){
dfn[u]=low[u]=++t;
s[++top]=u;vis[u]=1;
for(int i=0;i<g[u].size();++i){
int v=g[u][i];
if(!dfn[v]){
tarjan(v);low[u]=min(low[u],low[v]);
}else if(vis[v]) low[u]=min(low[u],low[v]);
}if(dfn[u]==low[u]){
vis[u]=0;
c[++sum]++;fa[u]=sum;
while(s[top]^u){
vis[st[top]]=0;
c[sum]++;fa[s[top--]]=sum;
}--top;
}
}
//割点
void tarjan(int u){
dfn[u]=low[u]=++t;int f=0;
for(int i=0;i<g[u].size();++i){
int v=g[u][i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
if(dfn[u]<=low[v]) ++f;
}else low[u]=min(low[u],dfn[v]);
}if((u==rt&&f>1)||(u!=rt&&f)) q.push(u);
}
//割边
void tarjan(int u){
dfn[u]=low[u]=++t;int f=0;
for(int i=0;i<g[u].size();++i){
int v=g[u][i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
if(dfn[u]<low[v]) a[++cnt]={min(u,v),max(u,v)};
}else low[u]=min(low[u],dfn[v]);
}
}
//点双
void tarjan(int u){
dfn[u]=low[u]=++t;st[++top]=u;int f=0;
for(int i=0;i<g[u].size();++i){
int v=g[u][i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);++f;
if(dfn[u]<=low[v]){
a[++ans].push_back(u);
while(st[top+1]!=v) a[ans].push_back(st[top--]);
}
}else low[u]=min(low[u],dfn[v]);
}if(u==rt&&!f) a[++ans].push_back(u);
}
//边双
void tarjan(int u,int fa){
dfn[u]=low[u]=++t;s[++top]=u;
for(in ti=0;i<g[u].size();++i){
int v=g[u][i];
if(!dfn[v]){
tarjan(v,u);
if(low[v]>=dfn[u]) continue;
low[u]=min(low[u],low[v]);
}else if(v^fa) low[u]=min(low[u],low[v]);
}if(dfn[u]==low[u]){
vis[u]=0;fa[u]=++sum;
while(s[top]^u){
vis[s[top]]=0;f[s[top--]]=sum;
}--top;
}
}
2-SAT
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+10;
int n,m,x,y,z1,z2,id[MAX][2],dfn[MAX],fa[MAX],low[MAX],s[MAX],t,top,vis[MAX],sum;
int tot,head[MAX];
struct edge{
int t,nxt;
} e[MAX];
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c<='9'&&c>='0'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
inline void add(int a,int b){
e[++tot].t=b;e[tot].nxt=head[a];head[a]=tot;
}void tarjan(int u){
dfn[u]=low[u]=++t;s[++top]=u;vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].t;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]) low[u]=min(low[u],dfn[v]);
}if(dfn[u]==low[u]){
vis[u]=0;
fa[u]=++sum;
while(s[top]!=u){
vis[s[top]]=0;
fa[s[top--]]=sum;
}top--;
}
}
int main(){
n=read();m=read();
for(int i=1,p=0;i<=n;++i)
for(int j=0;j<=1;++j) id[i][j]=++p;
for(int i=1;i<=m;++i){
x=read();z1=read();y=read();z2=read();
add(id[x][!z1],id[y][z2]);add(id[y][!z2],id[x][z1]);
}for(int i=1;i<=n<<1;++i)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;++i)
if(fa[id[i][0]]==fa[id[i][1]]){
cout<<"IMPOSSIBLE";return 0;
}
printf("POSSIBLE\n");
for(int i=1;i<=n;++i)
cout<<(fa[id[i][0]]>fa[id[i][1]])<<" ";
}
二次剩余
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,n,mod,a,x0,x1,ii;
struct com{
int r,i;
};
inline com operator*(com x,com y){
return {(x.r*y.r+ii*x.i%mod*x.i%mod)%mod,(x.i*y.r+x.r*y.i)%mod};
}
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^'0');c=getchar();}
return x;
}
inline int power(int a,int b){
int res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;b>>=1;
}return res;
}inline com power(com a,int b){
com res={1,0};
while(b){
if(b&1) res=res*a;
a=a*a;b>>=1;
}return res;
}inline void solve(){
do{
a=rand()%mod;
}while(!a||power((a*a%mod-n+mod)%mod,mod-1>>1)==1);
ii=(a*a%mod-n+mod)%mod;
x0=power({a,1},mod+1>>1).r;x1=mod-x0;
}
signed main(){
T=read();srand(time(0));
while(T--){
n=read();mod=read();
if(n==0){printf("0\n");continue;}
if(power(n,mod-1>>1)^1){printf("Hola!\n");continue;}
solve();printf("%lld %lld\n",x0,x1);
}
}
数据结构
带权并查集
int father(int x) {
if(x == fa[x]) return x;
int t=fa[x];
fa[x]=father(fa[x]);
val[x]=max(val[x],val[t]);
return fa[x];
}
堆
std::priority_queue<TypeName, Container, Compare> q;
// 使用 Container 作为底层容器,使用 Compare 作为比较类型
auto cmp = [](const std::pair<int, int> &l, const std::pair<int, int> &r) {
return l.second < r.second;
};
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >,decltype(cmp)>pq(cmp);
std::priority_queue<int> q1;//大根堆
std::priority_queue<int, std::vector<int> > q2;
std::priority_queue<int, std::deque<int>, std::greater<int> > q3;//小根堆
分块
inline int query(){//区间求和
ans=0;l=read();r=read();
for(int i=l;i<=min(r,block[l]*(int)sqrt(n));++i)
ans+=a[i];
if(block[l]==block[r]) return ans;
int b=(block[r]-1)*sqrt(n)+1;
for(int i=b;i<=r;++i) ans+=a[i];
for(int i=block[l]+1;i<=block[r]-1;++i) ans+=sum[i];
return ans;
}
inline void add(int y){//单点加
x=read();v=read()*y;
a[x]+=v;sum[block[x]]+=v;
}
单调队列
int q[N],head,tail;
void Calc() //滑动窗口,求连续k个的最小值
{
head=1,tail=0; //清空队列
for(int i=1;i<=n;i++) //枚举窗口右端
{
while(head<=tail && i-q[head]+1>k) q[head++]=0; //弹出已经离开窗口的元素
while(head<=tail && a[q[tail]]>a[i]) q[tail--]=0; //从队尾踢掉之前所有比当前元素大的数
q[++tail]=i; //当前元素自己加入队尾
if(i>=k) res[i-k+1]=q[head]; //完成以上操作后,队头即为最小值
}
return;
}
单调栈
数列中第 \(i\) 个元素之后第一个大于 \(a_i\) 的元素的下标
for(long long i=1;i<=n+1;++i)
{
if(S.empty() || a[S.top()]>=a[i]) S.push(i);
else
{
while(S.size() && a[S.top()]<a[i])
{
long long Top=S.top();
ans+=(i-Top-1);
S.pop();
}
S.push(i);
}
}
ST表
void init() {
for (int i = 1; i <= n; i++) st[i][0] = a[i];
for (int j = 1; (1<<j) <= n; j++)
for (int i = 1; i <= n - (1 << j) + 1; i++)
st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int ask(int l, int r) {
int k = log2(r - l + 1);
return max(st[l][k], st[r - (1 << k) + 1][k]);
}
树状数组
区间加,区间求和
int t1[MAXN], t2[MAXN], n;
int lowbit(int x) { return x & (-x); }
void add(int k, int v) {
int v1 = k * v;
while (k <= n) {
t1[k] += v, t2[k] += v1;
k += lowbit(k);
}
}
int getsum(int *t, int k) {
int ret = 0;
while (k) {
ret += t[k];
k -= lowbit(k);
}
return ret;
}
void add1(int l, int r, int v) {
add(l, v), add(r + 1, -v); // 将区间加差分为两个前缀加
}
long long getsum1(int l, int r) {
return (r + 1ll) * getsum(t1, r) - 1ll * l * getsum(t1, l - 1) -
(getsum(t2, r) - getsum(t2, l - 1));
}
二维树状数组
单点加,查询子矩阵和
void add(int x, int y, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
for (int j = y; j <= m; j += lowbit(j)) {
c[i][j] += v;
}
}
}
int sum(int x, int y) {
int res = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -= lowbit(j)) {
res += c[i][j];
}
}
return res;
}
int ask(int x1, int y1, int x2, int y2) {
// 查询子矩阵和
return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1);
}
子矩阵加,求子矩阵和
using ll = long long;
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z) {
for (int X = x; X <= n; X += lowbit(X))
for (int Y = y; Y <= m; Y += lowbit(Y)) {
t1[X][Y] += z;
t2[X][Y] += z * x; // 注意是 z * x 而不是 z * X,后面同理
t3[X][Y] += z * y;
t4[X][Y] += z * x * y;
}
}
void range_add(ll xa, ll ya, ll xb, ll yb,
ll z) { //(xa, ya) 到 (xb, yb) 子矩阵
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
ll ask(ll x, ll y) {
ll res = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
res += (x + 1) * (y + 1) * t1[i][j] - (y + 1) * t2[i][j] -
(x + 1) * t3[i][j] + t4[i][j];
return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb) {
return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}
线段树
线段树基础
建树
void build(int pos,int l,int r)
{
if(r<l) return;
if(l==r){scanf("%lf",&tree[pos].sum);return;}
int mid=l+r>>1;
build(pos*2,l,mid);build(pos*2+1,mid+1,r);
tree[pos].sum=tree[pos*2].sum+tree[pos*2+1].sum;
}
区间修改
void update(LL pos,LL l,LL r,LL ll,LL rr,LL num){
if(ll<=l&&rr>=r){
tree[pos].sum=tree[pos].sum*mod+(LL)x*(r-l+1);
laz1[pos]*=mod;tree[pos].laz2=tree[pos].laz2*mod+num;
return;
}LL mid=(l+r)>>1;pushdown(pos,mid-l+1,r-mid);
if(mid>=ll) update(pos<<1,l,mid,ll,rr,num);
if(mid<rr) update(pos<<1|1,mid+1,r,ll,rr,num);
tree[pos].sum=tree[pos<<1].sum+tree[pos<<1|1].sum;
}
懒标记(乘+加)
void pushdown(LL pos,LL len1,LL len2){
if(tree[pos].laz2){
laz1[pos<<1]*=laz1[pos];
laz1[pos<<1|1]*=laz1[pos];
tree[pos<<1].laz2=tree[pos<<1].laz2*laz1[pos]+tree[pos].laz2;
tree[pos<<1|1].laz2=tree[pos<<1|1].laz2*laz1[pos]+tree[pos].laz2;
tree[pos<<1].sum=tree[pos<<1].sum*laz1[pos]+tree[pos].laz2*len1;
tree[pos<<1|1].sum=tree[pos<<1|1].sum*laz1[pos]+tree[pos].laz2*len2;
laz1[pos]=1;tree[pos].laz2=0;
}
}
懒标记(区间更改)
void pushdown(LL pos,LL l1,LL l2){
if(tree[pos].laz){
tree[pos<<1].laz=tree[pos].laz;
tree[pos<<1|1].laz=tree[pos].laz;
tree[pos<<1].sum=l1*tree[pos].laz;
tree[pos<<1|1].sum=tree[pos].laz*l2;
tree[pos].laz=0;
}
}
区间查询
double query(long long pos,long long l,long long r,long long ll,long long rr)
{
if(l>rr||r<ll) return 0;
if(ll<=l&&r<=rr) return tree[pos].sum;
long long mid=(l+r)>>1;
pushdown(pos,mid-l+1,r-mid);
return query(pos*2,l,mid,ll,rr)+query(pos*2+1,mid+1,r,ll,rr);
}
单点查询
int query(int pos,int l,int r,int x){
if(l==r) return t[pos].sum;
int mid=(l+r)>>1;
if(mid>=x) return query(t[pos].ls,l,mid,x);
else return query(t[pos].rs,mid+1,r,x);
}
线段树合并
int merge(int ra,int rb,int l,int r){
if(!ra) return rb;
if(!rb) return ra;
if(l==r){
tree[ra].sum1+=tree[rb].sum1;
tree[ra].sum2+=tree[rb].sum2;
tree[ra].sum3+=tree[rb].sum3;
return ra;
}
int mid=(l+r)>>1;
ls(ra)=merge(ls(ra),ls(rb),l,mid);
rs(ra)=merge(rs(ra),rs(rb),mid+1,r);
pushup(ra);return ra;
}
吉司机线段树
void update(int pos,int l,int r,int x,int v){
if(x>=r){
if(t[pos].mx<x) return;
if(t[pos].ma<x){
t[pos].mx=t[pos].laz=v;return;
}
}int mid=l+r>>1;pushdown(pos);
update(pos<<1,l,mid,x,v);
if(x>mid) update(pos<<1|1,mid+1,r,x,v);
pushup(pos);
}int query(int pos,int l,int r,int x){
if(l==r) return t[pos].mx;
int mid=l+r>>1;pushdown(pos);
if(x<=mid) return query(pos<<1,l,mid,x);
else return query(pos<<1|1,mid+1,r,x);
}void pushup(int pos){
if(t[pos<<1].mx==t[pos<<1|1].mx){
t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz+t[pos<<1|1].siz;
t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].ma);return;
}if(t[pos<<1].mx>t[pos<<1|1].mx){
t[pos].mx=t[pos<<1].mx;t[pos].siz=t[pos<<1].siz;
t[pos].ma=max(t[pos<<1].ma,t[pos<<1|1].mx);return;
}t[pos].mx=t[pos<<1|1].mx;t[pos].siz=t[pos<<1|1].siz;
t[pos].ma=max(t[pos<<1|1].ma,t[pos<<1].mx);
}void pushdown(int pos){
if(t[pos].laz){
int l1=t[pos<<1].mx;
if(t[pos<<1].mx>=t[pos<<1|1].mx){
t[pos<<1].mx=t[pos<<1].laz=t[pos].laz;
}if(t[pos<<1|1].mx>=l1){
t[pos<<1|1].mx=t[pos<<1|1].laz=t[pos].laz;
}t[pos].laz=0;
}
}
李超线段树
要求在平面直角坐标系下维护两个操作:
- 在平面上加入一条线段。记第 \(i\) 条被插入的线段的标号为 \(i\)。
- 给定一个数 \(k\),询问与直线 \(x = k\) 相交的线段中,交点纵坐标最大的线段的编号。
inline bool work(int q,int w,int e){
if(!q) return 0;
double r=a[q].k*e+a[q].b,r1=a[w].k*e+a[w].b;
return r>r1||(r1-r<eps&&q<w);
}
void update(int pos,int l,int r,int ll,int rr,int u){
if(!u) return;
int mid=l+r>>1;
if(ll<=l&&rr>=r){
if(work(u,t[pos],mid)) swap(t[pos],u);
if(work(u,t[pos],l)) update(pos<<1,l,mid,ll,rr,u);
if(work(u,t[pos],r)) update(pos<<1|1,mid+1,r,ll,rr,u);
return;
}
if(ll<=mid) update(pos<<1,l,mid,ll,rr,u);
if(rr>mid) update(pos<<1|1,mid+1,r,ll,rr,u);
}void query(int pos,int l,int r,int k){
if(work(t[pos],ans,k)) ans=t[pos];
if(l==r) return;
int mid=l+r>>1;
if(k<=mid) query(pos<<1,l,mid,k);
else query(pos<<1|1,mid+1,r,k);
平衡树
splay
- 向 \(M\) 中插入一个数 \(x\)。
- 从 \(M\) 中删除一个数 \(x\)。(若有多个相同的数,应只删除一个)
- 查询 \(M\) 中有多少个数比 \(x\) 小,并且将得到的答案加 \(1\)。
- 查询如果将 \(M\) 从小到大排列后,排名位于第 \(x\) 位的数。
- 查询 \(M\) 中 \(x\) 的前驱(定义为 \(M\) 中小于 \(x\),且最大的数)。
- 查询 \(M\) 中 \(x\) 的后继(定义为 \(M\) 中大于 \(x\),且最小的数)。
#include<bits/stdc++.h>
using namespace std;
const int MAX=100010;
int son[MAX][2],val[MAX],fa[MAX],siz[MAX],cnt[MAX],tot,root,opt,x,n;
inline bool Dir(int x){return val[x]>val[fa[x]];}
void pushup(int x){ siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; }
inline void rotate(int x){
int y=fa[x],z=fa[y],k=Dir(x),w=son[x][k^1];
son[z][Dir(y)]=x; fa[x]=z;
son[x][k^1]=y; fa[y]=x;
son[y][k]=w; fa[w]=y;
pushup(x); pushup(y);
}
inline void splay(int x,int goal=0){
while(fa[x]!=goal){
int y=fa[x],z=fa[y];
if(z!=goal){
if(Dir(x)==Dir(y)) rotate(y);
else rotate(x);
}rotate(x);
}if(!goal) root=x;
}
inline void find(int x){
if(!root) return;
int cur=root;
while(son[cur][x>val[cur]]&&val[cur]!=x)
cur=son[cur][x>val[cur]];
splay(cur);
}
inline void ins(int x){
int cur=root,p=0;
while(cur&&val[cur]!=x)
p=cur,cur=son[cur][x>val[cur]];
if(cur) cnt[cur]++;
else{
cur=++tot;
if(p) son[p][x>val[p]]=cur;
son[cur][0]=son[cur][1]=0;
val[cur]=x;fa[cur]=p;
cnt[cur]=siz[cur]=1;
}splay(cur);
}
inline int las(int x){
find(x);
if(val[root]<x) return root;
int cur=son[root][0];
while(son[cur][1]) cur=son[cur][1];
splay(cur);return cur;
}
inline int nex(int x){
find(x);
if(val[root]>x) return root;
int cur=son[root][1];
while(son[cur][0]) cur=son[cur][0];
splay(cur);return cur;
}
inline void del(int x){
int l=las(x),r=nex(x);//
splay(l);splay(r,l);
int d=son[r][0];
if(cnt[d]>1){cnt[d]--;splay(d);}
else son[r][0]=0;
pushup(r);pushup(root);
}
inline int getrk(int x){
find(x);
return siz[son[root][0]]+(val[root]<x?cnt[root]:0);
}
inline int getth(int k){
int cur=root;
while(1){
if(k<=siz[son[cur][0]]&&son[cur][0])
cur=son[cur][0];
else
if(k>siz[son[cur][0]]+cnt[cur]){
k-=siz[son[cur][0]]+cnt[cur];
cur=son[cur][1];
}
else{
splay(cur);return val[cur];
}
}
}
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int main(){
//freopen("1.txt","r",stdin);
n=read();//cout<<n<<endl;
ins(-INT_MAX);ins(INT_MAX);
for(int i=1;i<=n;++i){
opt=read();x=read();
if(opt==1) ins(x);
if(opt==2) del(x);
if(opt==3) printf("%d\n",getrk(x));
if(opt==4) printf("%d\n",getth(x+1));
if(opt==5) printf("%d\n",val[las(x)]);
if(opt==6) printf("%d\n",val[nex(x)]);
//cout<<i<<" ";
}
}
treap
旋转treap
#include <iostream>
constexpr int MAXN = 100005;
constexpr int INF = 1 << 30;
int n;
struct treap { // 直接维护成数据结构,可以直接用
int l[MAXN], r[MAXN], val[MAXN], rnd[MAXN], size_[MAXN], w[MAXN];
int sz, ans, rt;
void pushup(int x) { size_[x] = size_[l[x]] + size_[r[x]] + w[x]; }
void lrotate(int &k) {
int t = r[k];
r[k] = l[t];
l[t] = k;
size_[t] = size_[k];
pushup(k);
k = t;
}
void rrotate(int &k) {
int t = l[k];
l[k] = r[t];
r[t] = k;
size_[t] = size_[k];
pushup(k);
k = t;
}
void insert(int &k, int x) { // 插入
if (!k) {
sz++;
k = sz;
size_[k] = 1;
w[k] = 1;
val[k] = x;
rnd[k] = rand();
return;
}
size_[k]++;
if (val[k] == x) {
w[k]++;
} else if (val[k] < x) {
insert(r[k], x);
if (rnd[r[k]] < rnd[k]) lrotate(k);
} else {
insert(l[k], x);
if (rnd[l[k]] < rnd[k]) rrotate(k);
}
}
bool del(int &k, int x) { // 删除节点
if (!k) return false;
if (val[k] == x) {
if (w[k] > 1) {
w[k]--;
size_[k]--;
return true;
}
if (l[k] == 0 || r[k] == 0) {
k = l[k] + r[k];
return true;
} else if (rnd[l[k]] < rnd[r[k]]) {
rrotate(k);
return del(k, x);
} else {
lrotate(k);
return del(k, x);
}
} else if (val[k] < x) {
bool succ = del(r[k], x);
if (succ) size_[k]--;
return succ;
} else {
bool succ = del(l[k], x);
if (succ) size_[k]--;
return succ;
}
}
int queryrank(int k, int x) {
if (!k) return 0;
if (val[k] == x)
return size_[l[k]] + 1;
else if (x > val[k]) {
return size_[l[k]] + w[k] + queryrank(r[k], x);
} else
return queryrank(l[k], x);
}
int querynum(int k, int x) {
if (!k) return 0;
if (x <= size_[l[k]])
return querynum(l[k], x);
else if (x > size_[l[k]] + w[k])
return querynum(r[k], x - size_[l[k]] - w[k]);
else
return val[k];
}
void querypre(int k, int x) {
if (!k) return;
if (val[k] < x)
ans = k, querypre(r[k], x);
else
querypre(l[k], x);
}
void querysub(int k, int x) {
if (!k) return;
if (val[k] > x)
ans = k, querysub(l[k], x);
else
querysub(r[k], x);
}
} T;
using std::cin;
using std::cout;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
srand(123);
cin >> n;
int opt, x;
for (int i = 1; i <= n; i++) {
cin >> opt >> x;
if (opt == 1)
T.insert(T.rt, x);
else if (opt == 2)
T.del(T.rt, x);
else if (opt == 3) {
cout << T.queryrank(T.rt, x) << '\n';
} else if (opt == 4) {
cout << T.querynum(T.rt, x) << '\n';
} else if (opt == 5) {
T.ans = 0;
T.querypre(T.rt, x);
cout << T.val[T.ans] << '\n';
} else if (opt == 6) {
T.ans = 0;
T.querysub(T.rt, x);
cout << T.val[T.ans] << '\n';
}
}
return 0;
}
无旋treap
int n,tot,dl,dr,tmp,rt,opt,x;
struct node{
int l,r,key,val,siz;
} t[MAX<<1];
inline int get(int x){
t[++tot].key=x;t[tot].val=rand();
t[tot].siz=1;return tot;
}inline void pushup(int pos){
t[pos].siz=t[t[pos].l].siz+t[t[pos].r].siz+1;
}void split(int pos,int x,int &l,int &r){
if(!pos){
l=r=0;return;
}if(t[pos].key<=x){
l=pos;split(t[l].r,x,t[l].r,r);
}else{
r=pos;split(t[r].l,x,l,t[r].l);
}pushup(pos);
}int merge(int l,int r){
if(!l||!r) return l|r;
if(t[l].val<=t[r].val){
t[l].r=merge(t[l].r,r);
pushup(l);return l;
}t[r].l=merge(l,t[r].l);
pushup(r);return r;
}inline void insert(int x){
split(rt,x-1,dl,dr);
rt=merge(merge(dl,get(x)),dr);
}inline void del(int x){
split(rt,x-1,dl,dr);
split(dr,x,tmp,dr);
tmp=merge(t[tmp].l,t[tmp].r);
rt=merge(merge(dl,tmp),dr);
}inline int getrk(int x){
split(rt,x-1,dl,dr);
int rk=t[dl].siz+1;
rt=merge(dl,dr);return rk;
}int getnum(int pos,int x){
int num=t[t[pos].l].siz+1;
if(num==x) return t[pos].key;
if(num>x) return getnum(t[pos].l,x);
return getnum(t[pos].r,x-num);
}inline int pre(int x){
split(rt,x-1,dl,dr);
int num=getnum(dl,t[dl].siz);
rt=merge(dl,dr);return num;
}inline int nxt(int x){
split(rt,x,dl,dr);
int num=getnum(dr,1);
rt=merge(dl,dr);return num;
}
可持久化
主席树
给出一个长度为n的序列a1an,有m次询问(x,y,k),每次询问a[x]a[y]内的第k小数。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
int n,m,k,c[MAX],opt,root[MAX],ll,rr,tot;
int a[MAX<<1],b[MAX<<1];
struct node{
int sum,ls,rs;
} t[MAX<<5];
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
void update(int,int&,int,int,int);
int query(int,int,int,int,int);
int main(){
//freopen("未命名4.txt","r",stdin);
//freopen("huashen.txt","w",stdout);
n=read();m=read();
for(int i=1;i<=n;++i) b[i]=a[i]=read();
sort(b+1,b+n+1);
int l=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n+m;++i)
a[i]=lower_bound(b+1,b+l+1,a[i])-b;
for(int i=1;i<=n;++i)
update(root[i-1],root[i],1,l,a[i]);
for(int i=1;i<=m;++i){
ll=read();rr=read();k=read();
printf("%d\n",b[query(root[ll-1],root[rr],1,l,k)]);
}
}
void update(int pre,int &pos,int l,int r,int x){
pos=++tot;t[pos]=t[pre];
t[pos].sum++;
if(l==r) return;
int mid=(l+r)>>1;
if(mid>=x) update(t[pre].ls,t[pos].ls,l,mid,x);
else update(t[pre].rs,t[pos].rs,mid+1,r,x);
}int query(int pre,int pos,int l,int r,int x){
if(l==r) return l;
int mid=(l+r)>>1;
int num=t[t[pos].ls].sum-t[t[pre].ls].sum;
if(num>=x) return query(t[pre].ls,t[pos].ls,l,mid,x);
else return query(t[pre].rs,t[pos].rs,mid+1,r,x-num);
}
可持久化平衡树
#include<bits/stdc++.h>
using namespace std;
const int MAX=5e5+10,inf=(1ll<<31)-1;
int n,v,op,x,rt[MAX],tot,dl,dr,tmp;
struct node{
int ls,rs,key,val,siz;
} t[MAX<<5];
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c<='9'&&c>='0'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
inline int get(int x){t[++tot]={0,0,x,rand(),1};return tot;}
inline void pushup(int pos){t[pos].siz=t[t[pos].ls].siz+t[t[pos].rs].siz+1;}
void split(int pos,int x,int &l,int &r){
if(!pos){l=r=0;return;}
int now=++tot;t[now]=t[pos];
if(t[now].key<=x){
l=now;split(t[l].rs,x,t[l].rs,r);
}else{
r=now;split(t[r].ls,x,l,t[r].ls);
}pushup(now);
}int merge(int l,int r){
if(!l||!r) return l|r;
if(t[l].val<=t[r].val){
t[l].rs=merge(t[l].rs,r);
pushup(l);return l;
}t[r].ls=merge(l,t[r].ls);
pushup(r);return r;
}
inline void ins(int &rt,int x){
split(rt,x-1,dl,dr);
rt=merge(merge(dl,get(x)),dr);
}inline void del(int &rt,int x){
split(rt,x-1,dl,tmp);split(tmp,x,tmp,dr);
tmp=merge(t[tmp].ls,t[tmp].rs);
rt=merge(merge(dl,tmp),dr);
}inline void getrk(int &rt,int x){
split(rt,x-1,dl,dr);printf("%d\n",t[dl].siz);
rt=merge(dl,dr);
}int getnum(int pos,int x){
int num=t[t[pos].ls].siz+1;
if(num==x) return t[pos].key;
if(num>x) return getnum(t[pos].ls,x);
return getnum(t[pos].rs,x-num);
}inline void getpre(int &rt,int x){
split(rt,x-1,dl,dr);printf("%d\n",getnum(dl,t[dl].siz));
rt=merge(dl,dr);
}inline void getnxt(int &rt,int x){
split(rt,x,dl,dr);printf("%d\n",getnum(dr,1));
rt=merge(dl,dr);
}
int main(){
n=read();ins(rt[0],inf);ins(rt[0],-inf);
for(int i=1;i<=n;++i){
v=read();op=read();x=read();
rt[i]=rt[v];
if(op==1) ins(rt[i],x);
if(op==2) del(rt[i],x);
if(op==3) getrk(rt[i],x);
if(op==4) printf("%d\n",getnum(rt[i],x+1));
if(op==5) getpre(rt[i],x);
if(op==6) getnxt(rt[i],x);
}
}
可持久化trie树
A x:添加操作,表示在序列末尾添加一个数 \(x\),序列的长度 \(N\) 加 \(1\)。Q l r x:询问操作,你需要找到一个位置 \(p\),满足 \(l \le p \le r\),使得:\(a[p] \oplus a[p+1] \oplus ... \oplus a[N] \oplus x\) 最大,输出最大值。
#include<bits/stdc++.h>
using namespace std;
const int MAX=6e5+10;
const int inf=1<<28;
int n,m,a[MAX],l,r,x,tr[MAX*28][2],cnt[MAX*28],ind,rt[MAX];
char op;
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
inline void add(int x){
int p=rt[x]=++ind,q=rt[x-1];cnt[p]=cnt[q]+1;
for(int i=28;i>=0;--i){
int u=(a[x]>>i)&1;
tr[p][0]=tr[q][0];tr[p][1]=tr[q][1];
p=tr[p][u]=++ind;q=tr[q][u];
cnt[p]=cnt[q]+1;
}
}inline int ask(int p,int q,int x){
int res=0;
for(int i=28;i>=0;--i){
int u=(x>>i)&1;
if(cnt[tr[p][u^1]]>cnt[tr[q][u^1]]){
res|=1<<i;p=tr[p][u^1];q=tr[q][u^1];
}else{p=tr[p][u];q=tr[q][u];}
}return res;
}
signed main(){
n=read();m=read();int p=rt[0]=++ind;cnt[p]=1;
for(int i=28;i>=0;--i) p=tr[p][0]=++ind,cnt[p]++;
for(int i=1;i<=n;++i) a[i]=read()^a[i-1],add(i);
while(m--){
cin>>op;
if(op=='A'){a[++n]=read()^a[n];add(n);}
else{
l=read();r=read();x=read();
cout<<ask(rt[r-1],l>=2?rt[l-2]:0,x^a[n])<<endl;
}
}
}
树套树
void update(int &rt,int l,int r,int x,int num){
if(!rt) rt=++tot;
t[rt].sum+=num;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) update(t[rt].ls,l,mid,x,num);
else update(t[rt].rs,mid+1,r,x,num);
}
int query(int l,int r,int k){
if(l==r) return l;
int num=0;
for(int i=1;i<=l2;++i) num+=t[t[pos[i]].ls].sum;
for(int i=1;i<=l1;++i) num-=t[t[pre[i]].ls].sum;
int mid=(l+r)>>1;
if(num>=k){
for(int i=1;i<=l1;++i) pre[i]=t[pre[i]].ls;
for(int i=1;i<=l2;++i) pos[i]=t[pos[i]].ls;
return query(l,mid,k);
}else{
for(int i=1;i<=l1;++i) pre[i]=t[pre[i]].rs;
for(int i=1;i<=l2;++i) pos[i]=t[pos[i]].rs;
return query(mid+1,r,k-num);
}
}
K-D Tree
#include <algorithm>
#include <iostream>
using namespace std;
constexpr int N(2e5), LG{18};
struct pt {
int x[2];
int v, sum;
int l, r;
int L[2], R[2];
} t[N + 5], l, h;
int rt[LG];
int b[N + 5], cnt;
void upd(int p) {
t[p].sum = t[t[p].l].sum + t[t[p].r].sum + t[p].v;
for (int k : {0, 1}) {
t[p].L[k] = t[p].R[k] = t[p].x[k];
if (t[p].l) {
t[p].L[k] = min(t[p].L[k], t[t[p].l].L[k]);
t[p].R[k] = max(t[p].R[k], t[t[p].l].R[k]);
}
if (t[p].r) {
t[p].L[k] = min(t[p].L[k], t[t[p].r].L[k]);
t[p].R[k] = max(t[p].R[k], t[t[p].r].R[k]);
}
}
}
int build(int l, int r, int dep = 0) {
int p{(l + r) >> 1};
nth_element(b + l, b + p, b + r + 1,
[dep](int x, int y) { return t[x].x[dep] < t[y].x[dep]; });
int x{b[p]};
if (l < p) t[x].l = build(l, p - 1, dep ^ 1);
if (p < r) t[x].r = build(p + 1, r, dep ^ 1);
upd(x);
return x;
}
void append(int &p) {
if (!p) return;
b[++cnt] = p;
append(t[p].l);
append(t[p].r);
p = 0;
}
int query(int p) {
if (!p) return 0;
bool flag{false};
for (int k : {0, 1}) flag |= (!(l.x[k] <= t[p].L[k] && t[p].R[k] <= h.x[k]));
if (!flag) return t[p].sum;
for (int k : {0, 1})
if (t[p].R[k] < l.x[k] || h.x[k] < t[p].L[k]) return 0;
int ans{0};
flag = false;
for (int k : {0, 1}) flag |= (!(l.x[k] <= t[p].x[k] && t[p].x[k] <= h.x[k]));
if (!flag) ans = t[p].v;
return ans += query(t[p].l) + query(t[p].r);
}
int main() {
int n;
cin >> n;
int lst{0};
n = 0;
while (true) {
int op;
cin >> op;
if (op == 1) {
int x, y, A;
cin >> x >> y >> A;
x ^= lst;
y ^= lst;
A ^= lst;
t[++n] = {{x, y}, A};
b[cnt = 1] = n;
for (int sz{0};; ++sz)
if (!rt[sz]) {
rt[sz] = build(1, cnt);
break;
} else
append(rt[sz]);
} else if (op == 2) {
cin >> l.x[0] >> l.x[1] >> h.x[0] >> h.x[1];
l.x[0] ^= lst;
l.x[1] ^= lst;
h.x[0] ^= lst;
h.x[1] ^= lst;
lst = 0;
for (int i{0}; i < LG; ++i) lst += query(rt[i]);
cout << lst << "\n";
} else
break;
}
return 0;
}
LCT
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
#define ls son[x][0]
#define rs son[x][1]
int f[MAX],son[MAX][2],a[MAX],val[MAX],st[MAX],laz[MAX],n,m,op,x,y;
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^'0');c=getchar();}
return x*f;
}
inline bool nrt(int x){return son[f[x]][0]==x||son[f[x]][1]==x;}
inline void pushup(int x){val[x]=val[ls]^val[rs]^a[x];}
inline void rev(int x){ls^=rs;rs^=ls;ls^=rs;laz[x]^=1;}
inline void pushdown(int x){
if(laz[x]){
rev(ls);rev(rs);laz[x]=0;
}
}inline void rotate(int x){
int y=f[x],z=f[y],k=son[y][1]==x,w=son[x][!k];
if(nrt(y)) son[z][son[z][1]==y]=x;
son[x][!k]=y;son[y][k]=w;
if(w) f[w]=y;f[y]=x;f[x]=z;
pushup(y);pushup(x);
}inline void splay(int x){
int y=x,z=0;
st[++z]=y;
while(nrt(st[z])) st[++z]=f[st[z]];
while(z) pushdown(st[z--]);
while(nrt(x)){
y=f[x];z=f[y];
if(nrt(y)){
if((son[y][1]==x)^(son[z][1]==y)) rotate(x);
else rotate(y);
}rotate(x);
}
}inline void access(int x){
for(int y=0;x;y=x,x=f[x]){
splay(x);rs=y;pushup(x);
}
}inline void markrt(int x){
access(x);
splay(x);
rev(x);
}inline int findrt(int x){
access(x);splay(x);
while(ls) pushdown(x),x=ls;
splay(x);return x;
}inline void split(int x,int y){
markrt(x);
access(y);splay(y);
}inline void link(int x,int y){
markrt(x);
if(findrt(y)^x) f[x]=y;
}inline void cut(int x,int y){
markrt(x);
if(findrt(y)==x&&f[y]==x&&!son[y][0]){
f[y]=rs=0;pushup(x);
}
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
while(m--){
op=read();x=read();y=read();
if(op==0){split(x,y);printf("%d\n",val[y]);}
if(op==1) link(x,y);
if(op==2) cut(x,y);
if(op==3){splay(x);a[x]=y;pushup(x);}
}
}
浙公网安备 33010602011771号