专栏文章
monkey cheng
P5612题解参与者 3已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @miqeg2pb
- 此快照首次捕获于
- 2025/12/04 03:27 3 个月前
- 此快照最后确认于
- 2025/12/04 03:27 3 个月前
不卡常,但是很难写。
只有排序操作就是一个颜色段均摊,加上区间异或操作颜色段要维护“排序后 ”的信息,还需支持分裂合并,采取 01-trie 维护。类似于线段树分裂合并,时空复杂度均为 。
具体来说,外层维护一颗线段树,线段树的叶子连向以这个点为左端点的颜色段的 01-trie。分裂 到 时直接把 01-trie 分裂,再把叶子节点的标记复制到 上。合并先各自下传叶子标记然后 01-trie 合并。这是因为分裂时的顺序应该是上次排序时的顺序,下传叶子节点标记就会变成异或之后的顺序。区间异或就直接打 tag。
使用压缩 01-trie,即只维护分叉点,空间可以达到 。合并时,需要根据最长公共前缀来新增节点;分裂时可以直接复制点和边,处理完之后检查这个点能不能被删除,这样不会使空间复杂度增大。
CPP#include<bits/stdc++.h>
using namespace std;
bool mst;
const int maxn=1e5+5,LIM=28,M=300000;
int n,q,a[maxn],xds[maxn<<2],add[maxn<<2],cnt[maxn<<2],leaf[maxn],C;
namespace Trie{
struct node{int ch,len,lv;node(){ch=len=lv=0;}};
vector<int> bin;
node t[2][M];
int sze[M],val[M],add[M],rt[maxn],tot=0;
node operator +(node A,node B){node C;C.ch=A.ch+B.ch,C.len=A.len+B.len,C.lv=A.lv+B.lv;return C;}
void clear(int p){sze[p]=0,val[p]=0,add[p]=0,t[0][p]=t[1][p]=node();}
int qsy(){
if(bin.size()){int u=bin.back();bin.pop_back();clear(u);return u;}
return ++tot;
}
void pushup(int k){
sze[k]=sze[t[0][k].ch]+sze[t[1][k].ch];
val[k]=val[t[0][k].ch]^val[t[1][k].ch];
}
inline int getv(int v,int l,int r){return (v>>l)&((1<<r-l+1)-1);}
void ADD(int k,int d,int v){
if(!k||!v)return ;
if(d>=0&&(v&(1<<d)))swap(t[0][k],t[1][k]);
if(t[0][k].ch)t[0][k].lv^=getv(v,d-t[0][k].len+1,d);
if(t[1][k].ch)t[1][k].lv^=getv(v,d-t[1][k].len+1,d);
add[k]^=v;val[k]^=((sze[k]&1)*v);
}
void pushdown(int k,int d){
if(!add[k]||!k||d<0)return ;
ADD(t[0][k].ch,d-t[0][k].len,add[k]);
ADD(t[1][k].ch,d-t[1][k].len,add[k]);
add[k]=0;
}
int cntch(int k){return (t[1][k].ch!=0)+(t[0][k].ch!=0);}
void check(int u,int k,int v,int d){
if(cntch(v)!=1)return ;
pushdown(u,d);pushdown(v,d-t[k][u].len);
int ch=t[0][v].ch+t[1][v].ch,len=t[0][v].len+t[1][v].len,lv=t[0][v].lv+t[1][v].lv;
t[k][u].ch=ch,t[k][u].lv=(t[k][u].lv<<len)+lv,t[k][u].len=len+t[k][u].len;
clear(v);bin.push_back(v);
}
void check(int u,int d){for(int i:{0,1})if(t[i][u].ch)check(u,i,t[i][u].ch,d);}
void split(int &x,int &y,int k,int d,int cur=0){
if(!k)return swap(x,y);
if(sze[x]==k)return ;
y=qsy();
if(d==-1){
int a=k,b=sze[x]-k;
val[x]=(a&1)*cur,val[y]=(b&1)*cur;
sze[x]=a,sze[y]=b;
return ;
}
pushdown(x,d),pushdown(y,d);
if(sze[t[0][x].ch]>=k){
t[1][y]=t[1][x];t[1][x]=node();
if(sze[t[0][x].ch]!=k)t[0][y].len=t[0][x].len,t[0][y].lv=t[0][x].lv;
split(t[0][x].ch,t[0][y].ch,k,d-t[0][x].len,cur^(t[0][x].lv<<(d-t[0][x].len+1)));
}else{
t[1][y].len=t[1][x].len,t[1][y].lv=t[1][x].lv;
split(t[1][x].ch,t[1][y].ch,k-sze[t[0][x].ch],d-t[1][x].len,cur^(t[1][x].lv<<(d-t[1][x].len+1)));
}
check(x,d),check(y,d);
pushup(x),pushup(y);
}
void INS(int u,int k,int v,int d){
int x=qsy();node tmp;
tmp.ch=x,tmp.lv=(t[k][u].lv>>(t[k][u].len-d)),tmp.len=d;int k2=(t[k][u].lv>>(t[k][u].len-d-1))&1;
t[k2][x].ch=v,t[k2][x].lv=(t[k][u].lv&((1<<t[k][u].len-d)-1)),t[k2][x].len=t[k][u].len-d;
t[k][u]=tmp;
pushup(x);
}
void SINS(int u,int v,int k){
int x=t[k][u].lv^t[k][v].lv;
if(x==0)return ;
int L=t[k][u].len-__lg(x)-1;
INS(u,k,t[k][u].ch,L),INS(v,k,t[k][v].ch,L);
}
int merge(int x,int &y,int d){
if(d<0){
val[x]^=val[y];
sze[x]+=sze[y];
clear(y),bin.push_back(y);y=0;
return x;
}
pushdown(x,d),pushdown(y,d);
for(auto i:{0,1}){
if(t[i][x].ch&&t[i][y].ch){
if(t[i][x].len>t[i][y].len)INS(x,i,t[i][x].ch,t[i][y].len);
else if(t[i][x].len<t[i][y].len)INS(y,i,t[i][y].ch,t[i][x].len);
SINS(x,y,i);
}
}
for(int i:{0,1}){
if(!t[i][x].ch||!t[i][y].ch)t[i][x]=t[i][x]+t[i][y];
else t[i][x].ch=merge(t[i][x].ch,t[i][y].ch,d-t[i][x].len);
}
clear(y),bin.push_back(y);y=0;
pushup(x);check(x,d);
return x;
}
void build(){
for(int i=1;i<=n;i++){
rt[i]=qsy();int k=(a[i]>>LIM)&1;
t[k][rt[i]].len=LIM+1,t[k][rt[i]].lv=a[i],t[k][rt[i]].ch=qsy();
sze[t[k][rt[i]].ch]=sze[rt[i]]=1,val[t[k][rt[i]].ch]=val[rt[i]]=a[i];
}
}
}
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1)
void ADD(int k,int v){xds[k]^=((cnt[k]&1)*v),add[k]^=v;}
void pushup(int k,int l,int r){
if(l<r)xds[k]=xds[ls]^xds[rs],cnt[k]=cnt[ls]+cnt[rs];
else cnt[k]=Trie::sze[Trie::rt[l]],xds[k]=Trie::val[Trie::rt[l]]^(add[k]*(cnt[k]&1));
}
void Pushdown(int k,int l){if(Trie::rt[l])Trie::ADD(Trie::rt[l],LIM,add[k]);add[k]=0;}
void pushdown(int k,int l,int r){if(l<r)ADD(ls,add[k]),ADD(rs,add[k]),add[k]=0;}
set<pair<int,int> > st;
int query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y)return xds[k];
pushdown(k,l,r);
int res=0;
if(x<=mid)res^=query(ls,l,mid,x,y);
if(mid<y)res^=query(rs,mid+1,r,x,y);
return res;
}
void Push(int k,int l,int r,int x){
if(l==r)return pushup(k,l,r);
pushdown(k,l,r);
if(x<=mid)Push(ls,l,mid,x);
else Push(rs,mid+1,r,x);
pushup(k,l,r);
}
void PPush(int k,int l,int r,int x){
if(l==r)return Pushdown(k,l),pushup(k,l,r);
pushdown(k,l,r);
if(x<=mid)PPush(ls,l,mid,x);
else PPush(rs,mid+1,r,x);
pushup(k,l,r);
}
void Push(int x){Push(1,1,n,x);}
void PPush(int x){PPush(1,1,n,x);}
void SPLIT(int x){
auto it=st.upper_bound((pair<int,int>){x,n+1});--it;
int l=(*it).first,r=(*it).second;
if(x==l)return ;
PPush(x),Push(l);
Trie::split(Trie::rt[l],Trie::rt[x],x-l,LIM);
Push(l);pushup(leaf[l],l,l);ADD(leaf[x],add[leaf[l]]);Push(x);
st.erase({l,r});st.insert({l,x-1});st.insert({x,r});
}
void modify(int k,int l,int r,int x,int y,int v){
if(x<=l&&r<=y)return ADD(k,v);
pushdown(k,l,r);
if(x<=mid)modify(ls,l,mid,x,y,v);
if(mid<y)modify(rs,mid+1,r,x,y,v);
pushup(k,l,r);
}
void build(int k,int l,int r){
if(l==r)return leaf[l]=k,pushup(k,l,r);
build(ls,l,mid);build(rs,mid+1,r);
pushup(k,l,r);
}
void MERGE(int x,int y){
PPush(x),PPush(y);
Trie::rt[x]=Trie::merge(Trie::rt[x],Trie::rt[y],LIM);
Push(x);Push(y);
}
void SORT(int l,int r){
SPLIT(l);if(r+1<=n)SPLIT(r+1);
auto it=st.upper_bound((pair<int,int>){l,0});
vector<pair<int,int>> V;
while((*it).first<=r)V.push_back(*it),++it;
for(auto u:V)PPush(u.first);
for(int i=1;i<V.size();i++)MERGE(V[0].first,V[i].first);
for(auto x:V)st.erase(x);
st.insert({l,r});
}
void pd(int k,int l,int r){
pushup(k,l,r);
if(l==r)return ;
pd(ls,l,mid),pd(rs,mid+1,r);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>q;
for(int i=0;i<=n+1;i++)st.insert({i,i});
for(int i=1;i<=n;i++)cin>>a[i];
Trie::build();build(1,1,n);
for(int i=1;i<=q;i++){
int tp,l,r,v;C=i;
cin>>tp>>l>>r;
if(tp==1){
cin>>v;
SPLIT(l);if(r+1<=n)SPLIT(r+1);
modify(1,1,n,l,r,v);
}else if(tp==2)SORT(l,r);
else{
SPLIT(l);if(r+1<=n)SPLIT(r+1);
cout<<query(1,1,n,l,r)<<endl;
}
}
return 0;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...