此解法超级暴力。洛谷最优解倒数……
因为为这道题只有(30)种颜色,所以我们可以用30颗线段树来分别维护每种颜色。
涂颜色就将对应颜色的线段树区间染色成(1),其他的染成(0)。
统计颜色就把线段树都枚举一遍,统计在这个区间上有(1)的线段树数量
然而正解是压位线段树
思路好想,理论时间复杂度也能过,就是常数大,在洛谷不开(O_2)过不去……
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct zzz{ //线段树
int tree[100010<<2],tag[100010<<2];
void build(int l,int r,int p){
if(l==r){
tree[p]=1; return ;
}
build(l,mid,ls); build(mid+1,r,rs);
tree[p]=tree[ls]+tree[rs];
}
inline void down(int l,int r,int p){
if(tag[p]==-1) return ;
tree[ls]=(mid-l+1)*tag[p];
tree[rs]=(r-mid)*tag[p];
tag[ls]=tag[p]; tag[rs]=tag[p]; tag[p]=-1;
}
void update(int l,int r,int p,int nl,int nr,int k){
if(l>=nl&&r<=nr){
tree[p]=k*(r-l+1); tag[p]=k;
return ;
}
down(l,r,p);
if(nl<=mid) update(l,mid,ls,nl,nr,k);
if(nr>mid) update(mid+1,r,rs,nl,nr,k);
tree[p]=tree[ls]+tree[rs];
}
int query(int l,int r,int p,int nl,int nr){
int ans=0;
if(l>=nl&&r<=nr) return tree[p];
down(l,r,p);
if(nl<=mid) ans+=query(l,mid,ls,nl,nr);
if(nr>mid) ans+=query(mid+1,r,rs,nl,nr);
return ans;
}
}color[31]; //三十颗线段树
inline int read(){
int k=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(f=='-') f=-1;
for(;c>='0'&&c<='9';c=getchar())
k=k*10+c-48;
return k*f;
}
inline char read_c(){
char c=getchar();
for(;c<'A'||c>'Z';) c=getchar();
for(;c>='A'&&c<='Z';)
return c;
}
int main(){
int n=read(),t=read(),m=read();
for(int i=1;i<=t;i++) memset(color[i].tag,-1,sizeof(color[i].tag));
color[1].build(1,n,1); //初始颜色全为1
for(int i=1;i<=m;i++){
char c=read_c();
if(c=='C'){
int x=read(),y=read(),z=read();
if(x>y) x^=y^=x^=y; //x^=y^=x^=y等价于swap(x,y)
for(int i=1;i<=t;i++){ //涂颜色
if(i==z) color[i].update(1,n,1,x,y,1);
else color[i].update(1,n,1,x,y,0);
}
}
else{
int x=read(),y=read(),anss=0;
if(x>y) x^=y^=x^=y;
for(int i=1;i<=t;i++){ //统计颜色
if(color[i].query(1,n,1,x,y)) ++anss;
}
printf("%d
",anss);
}
}
return 0;
}
第十个测试点刚好卡过