题解:P5511 决战
RainRecall · · 题解
大家好,我非常喜欢暴力数据结构,所以我用分块通过了这道题目。
我们发现我们不可能直接对原序列分块,因为原序列的长度高达
但是如果我们把相同的数维护成一段,每次增加的段数是
首先先看一下
还有一个问题,我们维护了很多个段,但是问的是数的个数,所以我们还要维护一个排过序的块的每段数的个数的前缀和,然后就没有问题了。
剩下两个操作其实是比较像的,我们可以采用传统操作,散块直接改,整块打标记,打标记其实不是很难打。拿操作
同理我们也可以得出操作
思考一下我们怎样进行这三个操作的,我们发现我们需要像珂朵莉树一样,把颜色段裂开进行操作。但是在裂开的过程中块内元素个数会增加,所以我们需要像块状链表一样,如果块长大于一定值,直接把它裂成两个,来稳定我们的复杂度。当然其实不用写链表,你直接加在后面,到时候全扫一遍判断即可。
时间复杂度
#include<bits/stdc++.h>
#define N 100005
#define B 137
using namespace std;
struct node{
int l,r,k;
};
bool operator<(node a,node b){
return a.k<b.k;
}
int len[N],dy[N],xy[N],Len,inf=2e9;
node a[N/B*4][B*3],b[N/B*4][B*3];
int c[N/B*4][B*3];
int bl(int x){
return a[x][1].l;
}
int br(int x){
return a[x][len[x]].r;
}
int findblock(int x){
for(int i=1;i<=Len;++i){
if(bl(i)<=x&&x<=br(i))return i;
}
return -1;
}
void pushdown(int x,int op=1){
for(int i=1;i<=len[x];++i){
if(a[x][i].k<xy[x])a[x][i].k=xy[x];
if(a[x][i].k>dy[x])a[x][i].k=dy[x];
b[x][i]=a[x][i];
}
xy[x]=-inf;dy[x]=inf;
if(op){
sort(b[x]+1,b[x]+len[x]+1);
c[x][0]=0;
for(int i=1;i<=len[x];++i)c[x][i]=c[x][i-1]+b[x][i].r-b[x][i].l+1;
}
}
int split(int x){
int qwq=findblock(x);
for(int i=1;i<=len[qwq];++i){
if(a[qwq][i].l==x)return i;
if(a[qwq][i].l<x&&x<=a[qwq][i].r){
pushdown(qwq,0);len[qwq]++;
for(int j=len[qwq];j>i;--j)a[qwq][j]=a[qwq][j-1];
a[qwq][i].r=x-1;a[qwq][i+1].l=x;
pushdown(qwq);return i+1;
}
}
return 0;
}
void boom(int x){
if(len[x]>=1.37*B){
++Len;int rr=0;
for(int i=len[x]/2+1;i<=len[x];++i)a[Len][++rr]=a[x][i];
len[Len]=len[x]-len[x]/2;dy[Len]=dy[x];xy[Len]=xy[x];len[x]/=2;
pushdown(x);
pushdown(Len);
}
}
void updmin(int l,int r,int h){
int L=split(l),R=split(r+1);
int ll=findblock(l),rr=findblock(r+1);
if(ll==rr){
pushdown(ll,0);
for(int i=L;i<R;++i)if(a[ll][i].k<h)a[ll][i].k=h;
pushdown(ll);
}
else{
pushdown(ll,0);
for(int i=L;i<=len[ll];++i)if(a[ll][i].k<h)a[ll][i].k=h;
pushdown(ll);
pushdown(rr,0);
for(int i=1;i<R;++i)if(a[rr][i].k<h)a[rr][i].k=h;
pushdown(rr);
for(int i=1;i<=Len;++i){
if(l<=bl(i)&&br(i)<=r&&i!=ll&&i!=rr)xy[i]=max(xy[i],h),dy[i]=max(dy[i],h);
}
}
boom(ll);boom(rr);
}
void updmax(int l,int r,int h){
int ll=findblock(l),rr=findblock(r+1);
int L=split(l),R=split(r+1);
if(ll==rr){
pushdown(ll,0);
for(int i=L;i<R;++i)if(a[ll][i].k>h)a[ll][i].k=h;
pushdown(ll);
}
else{
pushdown(ll,0);
for(int i=L;i<=len[ll];++i)if(a[ll][i].k>h)a[ll][i].k=h;
pushdown(ll);
pushdown(rr,0);
for(int i=1;i<R;++i)if(a[rr][i].k>h)a[rr][i].k=h;
pushdown(rr);
for(int i=1;i<=Len;++i){
if(l<=bl(i)&&br(i)<=r&&i!=ll&&i!=rr)xy[i]=min(xy[i],h),dy[i]=min(dy[i],h);
}
}
boom(ll);boom(rr);
}
int query(int l,int r,int h){
int ll=findblock(l),rr=findblock(r+1);
int L=split(l),R=split(r+1),ans=0;
if(ll==rr){
pushdown(ll,0);
for(int i=L;i<R;++i)ans+=(a[ll][i].k<h)*(a[ll][i].r-a[ll][i].l+1);
pushdown(ll);
}
else{
pushdown(ll,0);
for(int i=L;i<=len[ll];++i)ans+=(a[ll][i].k<h)*(a[ll][i].r-a[ll][i].l+1);
pushdown(ll);
pushdown(rr,0);
for(int i=1;i<R;++i)ans+=(a[rr][i].k<h)*(a[rr][i].r-a[rr][i].l+1);
pushdown(rr);
for(int i=1;i<=Len;++i){
if(l<=bl(i)&&br(i)<=r&&i!=ll&&i!=rr){
if(h<=xy[i])continue;
if(h>dy[i]){
ans+=br(i)-bl(i)+1;continue;
}
int ul=1,ur=len[i],aans=0;
while(ul<=ur){
int mid=(ul+ur)>>1;
if(b[i][mid].k<h)aans=mid,ul=mid+1;
else ur=mid-1;
}
ans+=c[i][aans];
}
}
}
boom(ll);boom(rr);
return ans;
}
int n,m,zx,yhb;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
cin>>n>>m>>zx;len[++Len]=1;
a[Len][1]=b[Len][1]={1,n+n,0};xy[Len]=-inf;dy[Len]=inf;
while(m--){
int op,l,r,h;cin>>op>>l>>r>>h;
if(zx)l^=yhb,r^=yhb,h^=yhb;
if(l>r)continue;
if(op==1)yhb=query(l,r,h),cout<<yhb<<'\n';
else if(op==2)updmax(l,r,h);
else updmin(l,r,h);
//print();
}
return 0;
}