题解:AT_abc430_g [ABC430G] Range Set Modifying Query
考虑珂朵莉树维护连续段。
这个插入删除一个值显然是一个珂朵莉树的板子。
对于每一种值都开一棵珂朵莉树,插入就是区间赋值
我们另外再用一棵线段树来维护每个位置的
那么对于 assign 操作就是从
由于我们每次都会把枚举过的连续段都删掉,枚举总量均摊是
::::success[Code]
const int N=3e5+5;
int n,Q;
struct Segment{
struct tree{int v,x;}tr[N<<2];
int lz[N<<2];
tree merge(tree x,tree y){
tree res;
if(x.v==y.v)res={x.v,x.x+y.x};
else if(x.v>y.v)res=x;
else res=y;
return res;
}
void Add(int x,int v){
lz[x]+=v;
tr[x].v+=v;
}
void push(int x){
Add(x<<1,lz[x]);
Add(x<<1|1,lz[x]);
lz[x]=0;
}
void add(int l,int r,int x,int L,int R,int v){
if(l!=r)push(x);
if(l>=L&&r<=R){
Add(x,v);
return;
}
int mid((l+r)>>1);
if(mid>=L)add(l,mid,x<<1,L,R,v);
if(mid<R)add(mid+1,r,x<<1|1,L,R,v);
tr[x]=merge(tr[x<<1],tr[x<<1|1]);
}
void bd(int l,int r,int x){
if(l==r){
tr[x]={0,1};
return;
}
int mid((l+r)>>1);
bd(l,mid,x<<1);
bd(mid+1,r,x<<1|1);
tr[x]=merge(tr[x<<1],tr[x<<1|1]);
}
tree query(int l,int r,int x,int L,int R){
if(l!=r)push(x);
if(l>=L&&r<=R)return tr[x];
int mid((l+r)>>1);
if(mid<L)return query(mid+1,r,x<<1|1,L,R);
if(mid>=R)return query(l,mid,x<<1,L,R);
return merge(query(l,mid,x<<1,L,R),query(mid+1,r,x<<1|1,L,R));
}
}T;
struct ODT{
struct node{
int l,r,v;
bool operator <(const node B)const{return l<B.l;}
};
set<node>s;
auto split(int x){
auto it=s.lower_bound({x,0,0});
if(it==s.begin()||it->l==x)return it;
--it;
int l=it->l,r=it->r,v=it->v;
s.erase(it);
s.insert({l,x-1,v});
return s.insert({x,r,v}).first;
}
void assign(int l,int r,int v){
auto ed=split(r+1),st=split(l);
for(auto it=st;it!=ed;++it){
int l=it->l,r=it->r,v=it->v;
T.add(1,n,1,l,r,-v);
}
s.erase(st,ed);
s.insert({l,r,v});
T.add(1,n,1,l,r,v);
}
}odt[65];
int main(){
scanf("%d%d",&n,&Q);
T.bd(1,n,1);
for(int i=1;i<=60;++i)odt[i].s.insert({1,n,0});
while(Q--){
int opt,l,r;
scanf("%d%d%d",&opt,&l,&r);
if(opt==1){
int x;
scanf("%d",&x);
odt[x].assign(l,r,1);
}
if(opt==2){
int x;
scanf("%d",&x);
odt[x].assign(l,r,0);
}
if(opt==3){
auto ans=T.query(1,n,1,l,r);
printf("%d %d\n",ans.v,ans.x);
}
}
return 0;
}
::::