ybtAu「高级数据结构」第7章 树套树
A. 【例题1】二维线段树
如题。注意需要在内层树的节点上维护所在外层树节点的子树上对应的内层节点。听起来有点绕,那就看看代码吧。
#include <iostream>
#include <cstring>
#define N 805
#define M 1000005
int n,m,a[N][N],mx[N<<3][N<<3],mn[N<<3][N<<3];
#define mid (lb+rb>>1)
namespace SGT2
{
void md(int x,int t,int k,int lb,int rb,bool fg,int fa)
{
//printf("\tmd %d: %d %d fg %d\n",x,t,k,fg);
if(lb==rb)
{
if(fg) mx[fa][x]=mn[fa][x]=k;
else mx[fa][x]=std::max(mx[fa<<1][x],mx[fa<<1|1][x]),
mn[fa][x]=std::min(mn[fa<<1][x],mn[fa<<1|1][x]);
return;
}
(t<=mid)?md(x<<1,t,k,lb,mid,fg,fa):md(x<<1|1,t,k,mid+1,rb,fg,fa);
mx[fa][x]=std::max(mx[fa][x<<1],mx[fa][x<<1|1]),mn[fa][x]=std::min(mn[fa][x<<1],mn[fa][x<<1|1]);
}
int qmx(int x,int l,int r,int lb,int rb,int fa)
{
if(l<=lb&&rb<=r) return mx[fa][x];
int ret=-1e9;
if(l<=mid) ret=qmx(x<<1,l,r,lb,mid,fa);
if(r>mid) ret=std::max(ret,qmx(x<<1|1,l,r,mid+1,rb,fa));
return ret;
}
int qmn(int x,int l,int r,int lb,int rb,int fa)
{
if(l<=lb&&rb<=r) return mn[fa][x];
int ret=1e9;
if(l<=mid) ret=qmn(x<<1,l,r,lb,mid,fa);
if(r>mid) ret=std::min(ret,qmn(x<<1|1,l,r,mid+1,rb,fa));
return ret;
}
};
namespace SGT1
{
void md(int x,int t,int v,int k,int lb,int rb)
{
if(lb<rb) (t<=mid)?md(x<<1,t,v,k,lb,mid):md(x<<1|1,t,v,k,mid+1,rb);
SGT2::md(1,v,k,1,n,lb==rb,x);
}
int qmx(int x,int l1,int r1,int l2,int r2,int lb,int rb)
{
if(l1<=lb&&rb<=r1) return SGT2::qmx(1,l2,r2,1,n,x);
int ret=-1e9;
if(l1<=mid) ret=qmx(x<<1,l1,r1,l2,r2,lb,mid);
if(r1>mid) ret=std::max(ret,qmx(x<<1|1,l1,r1,l2,r2,mid+1,rb));
return ret;
}
int qmn(int x,int l1,int r1,int l2,int r2,int lb,int rb)
{
if(l1<=lb&&rb<=r1) return SGT2::qmn(1,l2,r2,1,n,x);
int ret=1e9;
if(l1<=mid) ret=qmn(x<<1,l1,r1,l2,r2,lb,mid);
if(r1>mid) ret=std::min(ret,qmn(x<<1|1,l1,r1,l2,r2,mid+1,rb));
return ret;
}
};
#undef mid
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
int T;
std::cin>>T;
for(int cases=1;cases<=T;cases++)
{
memset(mn,0x3f,sizeof mn);
std::cin>>n;
for(int i=1;i<=n;i++) for(int j=1,x;j<=n;j++) std::cin>>x,SGT1::md(1,i,j,x,1,n);
std::cin>>m;
std::cout<<"Case #"<<cases<<":\n";
for(int i=1,x,y,l;i<=m;i++)
{
std::cin>>x>>y>>l;
int tx=x-(l>>1),ty=y-(l>>1);
int mx=SGT1::qmx(1,tx,tx+l-1,ty,ty+l-1,1,n),mn=SGT1::qmn(1,tx,tx+l-1,ty,ty+l-1,1,n);
//printf("Rect %d %d %d %d mx %d mn %d\n",tx,ty,tx+l-1,ty+l-1,mx,mn);
std::cout<<(mx+mn>>1)<<'\n';
SGT1::md(1,x,y,mx+mn>>1,1,n);
}
}
}
B. 【例题2】矩阵修改查询
毒瘤卡常题。没卡过。
C. 【例题3】三维俄罗斯方块
查询矩阵最大值,然后矩阵覆盖。
需要用到标记永久化的思想,外层树每个节点维护两棵树,一棵存值,一棵存 tag,走到一个节点,就在存值的树上修改;如果第一维覆盖该节点,那么在 tag 树上做第二维区间修改,否则递归下去。查询时,查询经过节点的 tag 树,如果查询区间覆盖该节点,那么也查询存值的树。
由于值只会增加,所以免去了一些细节。
这题相比上题没有那么卡常。
#include <iostream>
#define N 1005
int n,m,q;
#define mid (lb+rb>>1)
struct Node
{
Node *ls,*rs;
int d,tg;
Node():ls(nullptr),rs(nullptr),d(0),tg(0) {}
void pu(int x) {d=0;if(ls) d=ls->d;if(rs) d=std::max(d,rs->d);}
void mt(int x) {d=std::max(d,x),tg=std::max(tg,x);}
void pd()
{
if(!tg) return;
if(!ls) ls=new Node();
if(!rs) rs=new Node();
ls->mt(tg),rs->mt(tg),tg=0;
}
};
namespace SGT2
{
void md(Node *&x,int l,int r,int t,int lb,int rb)
{
if(!x) x=new Node();
if(l<=lb&&rb<=r) return x->mt(t),void();
x->pd();
x->d=std::max(x->d,t);
if(l<=mid) md(x->ls,l,r,t,lb,mid);
if(r>mid) md(x->rs,l,r,t,mid+1,rb);
}
int qr(Node *x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return x->d;
x->pd();
int ret=0;
if(l<=mid) ret=qr(x->ls,l,r,lb,mid);
if(r>mid) ret=std::max(ret,qr(x->rs,l,r,mid+1,rb));
return ret;
}
};
namespace SGT1
{
Node *rt[N<<2],*tg[N<<2];
void md(int x,int l1,int r1,int l2,int r2,int k,int lb,int rb)
{
SGT2::md(rt[x],l2,r2,k,0,m);
if(l1<=lb&&rb<=r1) return SGT2::md(tg[x],l2,r2,k,0,m),void();
if(l1<=mid) md(x<<1,l1,r1,l2,r2,k,lb,mid);
if(r1>mid) md(x<<1|1,l1,r1,l2,r2,k,mid+1,rb);
}
int qr(int x,int l1,int r1,int l2,int r2,int lb,int rb)
{
if(l1<=lb&&rb<=r1) return std::max(SGT2::qr(rt[x],l2,r2,0,m),SGT2::qr(tg[x],l2,r2,0,m));
int ret=SGT2::qr(tg[x],l2,r2,0,m);
if(l1<=mid) ret=std::max(ret,qr(x<<1,l1,r1,l2,r2,lb,mid));
if(r1>mid) ret=std::max(ret,qr(x<<1|1,l1,r1,l2,r2,mid+1,rb));
return ret;
}
};
#undef mid
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m>>q;
for(int i=1,r,c,h,x,y;i<=q;i++)
{
std::cin>>r>>c>>h>>x>>y;
int mx=SGT1::qr(1,x,x+r-1,y,y+c-1,0,n)+h;
SGT1::md(1,x,x+r-1,y,y+c-1,mx,0,n);
}
std::cout<<SGT1::qr(1,0,n,0,m,0,n);
}
D. 【例题4】动态排名
分块是好想的
树状数组套权值线段树板子。
查询区间,是在树状数组上差分。记录查 \(r\) 时经过哪些树,查 \(l\) 时经过哪些树,在这 \(O(\log n)\) 棵权值线段树上二分即可。
#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>
#define N 100005
int n,m,a[N],len;
std::vector<int> b,g1,g2;
std::pair<std::pair<int,int>,std::pair<int,int> > q[N];
namespace SGT
{
int d[N<<7],ls[N<<7],rs[N<<7],idx;
#define mid (lb+rb>>1)
void md(int &x,int t,int k,int lb,int rb)
{
if(!x) x=++idx,d[x]=ls[x]=rs[x]=0;
d[x]+=k;
if(lb<rb) (t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb);
}
int qr(int k,int lb,int rb)
{
if(lb==rb) return lb;
int dt=0;
for(int i:g1) dt+=d[ls[i]];
for(int i:g2) dt-=d[ls[i]];
if(k<=dt)
{
for(int &i:g1) i=ls[i];
for(int &i:g2) i=ls[i];
return qr(k,lb,mid);
}
else
{
for(int &i:g1) i=rs[i];
for(int &i:g2) i=rs[i];
return qr(k-dt,mid+1,rb);
}
}
#undef mid
};
namespace BIT
{
int rt[N];
void c(int x,int t,int k) {for(;x<=n;x+=x&-x) SGT::md(rt[x],t,k,0,len);}
int q(int l,int r,int k)
{
g1.clear(),g2.clear();
for(;r;r-=r&-r) g1.push_back(rt[r]);
for(l--;l;l-=l&-l) g2.push_back(rt[l]);
return SGT::qr(k,0,len);
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
while(std::cin>>n>>m)
{
b.clear();
SGT::idx=0;
for(int i=1;i<=n;i++) BIT::rt[i]=0;
for(int i=1;i<=n;i++) std::cin>>a[i],b.push_back(a[i]);
for(int i=1,x,y,k;i<=m;i++)
{
char op;
std::cin>>op>>x>>y;
if(op=='Q') std::cin>>k,q[i]={{1,x},{y,k}};
if(op=='C') b.push_back(y),q[i]={{0,x},{y,0}};
}
std::sort(b.begin(),b.end());
b.erase(std::unique(b.begin(),b.end()),b.end());
len=b.size();
for(int i=1;i<=n;i++) a[i]=std::lower_bound(b.begin(),b.end(),a[i])-b.begin(),BIT::c(i,a[i],1);
for(int i=1;i<=m;i++)
{
int op=q[i].first.first,x=q[i].first.second,y=q[i].second.first,k=q[i].second.second;
if(op==1) std::cout<<b[BIT::q(x,y,k)]<<'\n';
if(op==0)
{
y=std::lower_bound(b.begin(),b.end(),y)-b.begin();
BIT::c(x,a[x],-1),BIT::c(x,y,1),a[x]=y;
}
}
}
}
E. 【例题5】二逼平衡树
主要做法同上题,其他操作按照正常权值线段树的做法实现。
#include <iostream>
#include <algorithm>
#include <vector>
#define N 100005
#define int long long
int n,m,a[N],len,lis[N];
std::pair<int,int> b[N<<1];
std::pair<std::pair<int,int>,std::pair<int,int> > q[N];
std::vector<int> rts,lts;
namespace SGT
{
int d[N<<7],ls[N<<7],rs[N<<7],idx;
#define mid (lb+rb>>1)
void ins(int &x,int t,int k,int lb,int rb)
{
if(!x) x=++idx;
d[x]+=k;
if(lb==rb) return;
(t<=mid)?ins(ls[x],t,k,lb,mid):ins(rs[x],t,k,mid+1,rb);
}
int qrk(int t,int lb,int rb)
{
if(lb==rb) return 0;
int suml=0;
for(int i:rts) suml+=d[ls[i]];
for(int i:lts) suml-=d[ls[i]];
if(t<=mid)
{
for(int &i:rts) i=ls[i];
for(int &i:lts) i=ls[i];
return qrk(t,lb,mid);
}
else
{
for(int &i:rts) i=rs[i];
for(int &i:lts) i=rs[i];
return suml+qrk(t,mid+1,rb);
}
}
int qval(int t,int lb,int rb)
{
if(lb==rb) return lb;
int sums=0,suml=0;
for(int i:rts) sums+=d[i],suml+=d[ls[i]];
for(int i:lts) sums-=d[i],suml-=d[ls[i]];
//printf("range %d %d: %d\n",lb,rb,sums);
if(!t||t>sums) return -1;
if(t<=suml)
{
for(int &i:rts) i=ls[i];
for(int &i:lts) i=ls[i];
return qval(t,lb,mid);
}
else
{
for(int &i:rts) i=rs[i];
for(int &i:lts) i=rs[i];
return qval(t-suml,mid+1,rb);
}
}
int qpre(int t)
{
std::vector<int> t1=rts,t2=lts;
int rk=qrk(t,1,len)+1;
rts=t1,lts=t2;
return qval(rk-1,1,len);
}
int qnxt(int t)
{
//printf("qnxt %d\n",t);
std::vector<int> t1=rts,t2=lts;
int rk=qrk(t+1,1,len);
rts=t1,lts=t2;
return qval(rk+1,1,len);
}
#undef mid
};
struct BIT
{
int rt[N];
void c(int x,int t,int k) {for(;x<=n;x+=x&-x) SGT::ins(rt[x],t,k,1,len);}
int q(int l,int r,int t,int op)
{
lts.clear(),rts.clear();
for(;r;r-=r&-r) rts.push_back(rt[r]);
for(l--;l;l-=l&-l) lts.push_back(rt[l]);
if(op==1) return SGT::qrk(t,1,len)+1;
if(op==2) return lis[SGT::qval(t,1,len)]; //
if(op==4)
{
int ret=SGT::qpre(t);
if(ret==-1) return -2147483647;
else return lis[ret]; //
}
if(op==5)
{
int ret=SGT::qnxt(t);
if(ret==-1) return 2147483647;
else return lis[ret]; //
}
}
} tr;
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++) std::cin>>a[i],b[++cnt]={a[i],-i};
for(int i=1,op,x,y,k;i<=m;i++)
{
std::cin>>op>>x>>y;
if(op!=3) std::cin>>k;
else k=y;
q[i]={{op,x},{y,k}};
if(op!=2) b[++cnt]={k,i};
}
std::sort(b+1,b+cnt+1);
b[0].first=-1;
for(int i=1;i<=cnt;i++)
{
if(b[i].first!=b[i-1].first) lis[++len]=b[i].first;
if(b[i].second<0) a[-b[i].second]=len;
if(b[i].second>0) q[b[i].second].second.second=len;
}
// for(int i=1;i<=len;i++) printf("%d;\n",lis[i]);
// for(int i=1;i<=n;i++) printf("%d ",a[i]);
// printf("\n");
for(int i=1;i<=n;i++) tr.c(i,a[i],1);
for(int i=1,op,x,y,k;i<=m;i++)
{
op=q[i].first.first,x=q[i].first.second,y=q[i].second.first,k=q[i].second.second;
if(op==3) tr.c(x,a[x],-1),tr.c(x,a[x]=k,1);//,printf("ch %d %d %d\n",3,x,k);
else std::cout<<tr.q(x,y,k,op)<<'\n';//,printf("qr %d %d %d %d\n",op,x,y,k);
}
}
F. 三维偏序
先按 \(a\) 排序,把剩下两维作为坐标,插入树状数组套权值线段树中,查询时在树套树上查询矩阵和。注意需要离散化。
#include <iostream>
#include <algorithm>
#define N 200005
std::pair<int,std::pair<int,int> > a[N],b[N];
int n,len,K,ans[N],rep[N];
namespace SGT
{
int d[N<<8],ls[N<<8],rs[N<<8],idx;
#define mid (lb+rb>>1)
void md(int &x,int t,int k,int lb,int rb)
{
if(!x) x=++idx;
d[x]+=k;
if(lb<rb) (t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb);
}
int qr(int x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return d[x];
int ret=0;
if(l<=mid) ret=qr(ls[x],l,r,lb,mid);
if(r>mid) ret+=qr(rs[x],l,r,mid+1,rb);
return ret;
}
#undef mid
};
namespace BIT
{
int rt[N],r;
void c(int x,int y,int k) {for(;x<=K;x+=x&-x) SGT::md(rt[x],y,k,1,K);}
int q(int x,int y) {for(r=0;x;x-=x&-x) r+=SGT::qr(rt[x],1,y,1,K);return r;}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>K;
for(int i=1,x,y,z;i<=n;i++) std::cin>>x>>y>>z,a[i]={x,{y,z}};
std::sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
if(a[i]!=a[i-1]) b[++len]=a[i];
rep[len]++;
}
for(int i=1;i<=len;i++)
{
int x=b[i].second.first,y=b[i].second.second;
BIT::c(x,y,rep[i]);
int sum=BIT::q(x,y)-1;
ans[sum]+=rep[i];
}
for(int i=0;i<n;i++) std::cout<<ans[i]<<'\n';
}
G. 动态逆序对
树状数组套权值线段树,一开始求出序列总的逆序对个数,删除每个数时算出删了它给答案带来的影响。
#include <iostream>
#define N 100005
#define int long long
int n,m,a[N],p[N];
namespace SGT
{
int d[N<<7],ls[N<<7],rs[N<<7],idx;
#define mid (lb+rb>>1)
void md(int &x,int t,int k,int lb,int rb)
{
if(!x) x=++idx;
d[x]+=k;
if(lb<rb) (t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb);
}
int qr(int x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return d[x];
int ret=0;
if(l<=mid) ret=qr(ls[x],l,r,lb,mid);
if(r>mid) ret+=qr(rs[x],l,r,mid+1,rb);
return ret;
}
#undef mid
};
namespace BIT
{
int rt[N],r;
void c(int x,int y,int k) {for(;x<=n;x+=x&-x) SGT::md(rt[x],y,k,1,n);}
int q1(int x,int y) {for(r=0;x;x-=x&-x) r+=SGT::qr(rt[x],y,n,1,n);return r;}
int q2(int x,int y) {for(r=0;x;x-=x&-x) r+=SGT::qr(rt[x],1,y,1,n);return r;}
};
namespace BT
{
int f[N],r;
void c(int x,int k) {for(;x<=n;x+=x&-x) f[x]+=k;}
int q(int x) {for(r=0;x;x-=x&-x) r+=f[x];return r;}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
int ans=0;
for(int i=1;i<=n;i++) std::cin>>a[i],BIT::c(i,a[i],1),p[a[i]]=i;
for(int i=n;i>=1;i--) ans+=BT::q(a[i]),BT::c(a[i],1);
for(int i=1,x;i<=m;i++)
{
std::cout<<ans<<'\n';
std::cin>>x;
BIT::c(p[x],x,-1);
ans-=BIT::q1(p[x]-1,x)+BIT::q2(n,x)-BIT::q2(p[x],x);
}
}
H. 存储器
单点修改插入删除,求区间内与区间次大值异或和最大的数。
由于有插入和删除,使用块链实现。由于需要快速查询整块中与某数异或和最大的数,所以使用 线性基 Trie。
具体地,在每个块维护最大、次大值和一棵 Trie,插入正常插入,对于修改、删除和分裂,由于对 Trie 和次大值都有影响,考虑暴力重构。查询时,先查次大值,遍历两边散块,再用中间整块的最大值和次大值更新;得到次大值后,先遍历两边散块,再在中间每块的 Trie 上查异或和最大的数。时间复杂度 \(O(m\sqrt n\log n)\)。
#include <iostream>
#include <vector>
#define N 2000005
#define mod 1048576
const int L=305;
int n,m,a[N];
namespace Trie
{
int tr[N][2],idx,st[N],tp;
int nd() {return tp?st[tp--]:++idx;}
void ins(int &rt,int x)
{
if(!rt) rt=nd();
for(int i=31,u=rt;i>=0;i--) {int &ch=tr[u][x>>i&1];if(!ch) ch=nd();u=ch;}
}
int qr(int rt,int x)
{
int ret=0,ch;
for(int i=31,u=rt;i>=0;i--) ch=x>>i&1,(tr[u][ch^1])?(u=tr[u][ch^1],ret|=1<<i):(u=tr[u][ch]);
return ret;
}
void del(int u)
{
if(!u) return;
del(tr[u][0]),del(tr[u][1]),tr[u][0]=tr[u][1]=0,st[++tp]=u;
}
};
struct Semi
{
int mx,sm;
Semi():mx(0),sm(0) {}
void ins(int x) {if(x>mx) std::swap(mx,sm),mx=x;else if(x>sm) sm=x;}
};
namespace Rope
{
int idx;
struct Node
{
Node *pre,*nxt;
std::vector<int> vc;
Semi pq;
int Trt;
Node():pre(nullptr),nxt(nullptr),Trt(0) {}
int operator [](int g) {return vc[g];}
void clear() {vc.clear(),pq.mx=pq.sm=0,Trie::del(Trt),Trt=0;}
void ins(int x) {vc.push_back(x),pq.ins(x),Trie::ins(Trt,x);}
void upd(int x) {pq.ins(x),Trie::ins(Trt,x);}
int qxor(int x) {return Trie::qr(Trt,x);}
int siz() {return vc.size();}
std::vector<int>::iterator bg() {return vc.begin();}
} pool[5005],*hed;
void rebuild(Node *p)
{
std::vector<int> tmp=p->vc;
p->clear();
for(int i:tmp) p->ins(i);
}
void split(Node *p)
{
Node *q=&pool[++idx];
q->pre=p,q->nxt=p->nxt,p->nxt=q;
if(q->pre) q->pre->nxt=q;
for(int i=L;i<p->siz();i++) q->ins((*p)[i]);
(p->vc).erase(p->bg()+L,(p->vc).end());
rebuild(p);
}
void build()
{
Node *p=hed=&pool[++idx];
for(int i=0;i<n;i++)
{
p->ins(a[i]);
if(p->siz()>=2*L) split(p),p=p->nxt;
}
}
void ins(int x,int t)
{
//printf("ins %d %d\n",x,t);
Node *p=hed;
while(p&&x>=p->siz()) x-=p->siz(),p=p->nxt;
if(!p) {p=hed;while(p->nxt) p=p->nxt,p->ins(t);}
else (p->vc).emplace((p->vc).begin()+x,t),p->upd(t);
if(p->siz()>=2*L) split(p);
//for(int i:p->vc) printf("%d,",i);
//printf("\n");
}
void del(int x)
{
//printf("del %d\n",x);
Node *p=hed;
while(p&&x>=p->siz()) x-=p->siz(),p=p->nxt;
//printf("erase %d\n",(*p)[x]);
(p->vc).erase((p->vc).begin()+x);
//for(int i:p->vc) printf("%d,",i);
//printf("\n");
if(!p->siz())
{
Trie::del(p->Trt);
if(p==hed) hed=p->nxt;
if(p->nxt) p->nxt->pre=p->pre;
if(p->pre) p->pre->nxt=p->nxt;
p->pre=p->nxt=nullptr;
}
else rebuild(p);
}
void md(int x,int t)
{
Node *p=hed;
while(p&&x>=p->siz()) x-=p->siz(),p=p->nxt;
(p->vc)[x]=t,rebuild(p);
}
int qr(int l,int r)
{
//printf("qr %d %d\n",l,r);
Node *lc=hed,*rc=hed;
while(lc&&l>=lc->siz()) l-=lc->siz(),lc=lc->nxt;
while(rc&&r>=rc->siz()) r-=rc->siz(),rc=rc->nxt;
if(lc==rc)
{
// printf("check1 sz %d\n",lc->siz());
Semi t;
for(int i=l;i<=r;i++) t.ins((*lc)[i]);
int ret=0;
for(int i=l;i<=r;i++) ret=std::max(ret,t.sm^(*lc)[i]);
// printf("ans=%d\n",ret);
return ret;
}
Semi t;
for(Node *p=lc->nxt;p!=rc;p=p->nxt) t.ins((p->pq).mx),t.ins((p->pq).sm); //lc->nxt
for(int i=l;i<lc->siz();i++) t.ins((*lc)[i]);
for(int i=0;i<=r;i++) t.ins((*rc)[i]);
int ret=0;
for(Node *p=lc->nxt;p!=rc;p=p->nxt) ret=std::max(ret,p->qxor(t.sm));//,printf("ret %d\n",ret);
for(int i=l;i<lc->siz();i++) ret=std::max(ret,t.sm^(*lc)[i]);
for(int i=0;i<=r;i++) ret=std::max(ret,t.sm^(*rc)[i]);
//printf("ans=%d\n",ret);
return ret;
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
for(int i=0;i<n;i++) std::cin>>a[i];
Rope::build();
int la=0,sz=n;
for(int i=1,x,y;i<=m;i++)
{
char op;
std::cin>>op>>x;
x=(x+la)%sz;
if(op=='I') std::cin>>y,y=(y+la)%mod,Rope::ins(x,y),sz++;
if(op=='D') Rope::del(x),sz--;
if(op=='C') std::cin>>y,y=(y+la)%mod,Rope::md(x,y);
if(op=='F') std::cin>>y,y=(y+la)%sz,std::cout<<(la=Rope::qr(x,y))<<'\n';
}
}
运行时间 \(11595\) ms。常数这一块

浙公网安备 33010602011771号