P1558 维护多棵线段树
色板游戏
题目背景
阿宝上学了,今天老师拿来了一块很长的涂色板。
题目描述
色板长度为 \(L\),\(L\) 是一个正整数,所以我们可以均匀地将它划分成 \(L\) 块 \(1\) 厘米长的小方格。并从左到右标记为 \(1, 2, \dots L\)。
现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:
C A B C
指在 \(A\) 到 \(B\) 号方格中涂上颜色 \(C\)。P A B
指老师的提问:\(A\) 到 \(B\) 号方格中有几种颜色。
学校的颜料盒中一共有 \(T\) 种颜料。为简便起见,我们把他们标记为 \(1, 2, \dots T\). 开始时色板上原有的颜色就为 \(1\) 号色。 面对如此复杂的问题,阿宝向你求助,你能帮助他吗?
输入格式
第一行有3个整数 \(L (1 \le L \le 10^5), T (1 \le T \le 30) 和 O (1 \le O \le 10^5)\)。 在这里 \(O\) 表示事件数。
接下来 \(O\) 行, 每行以 C A B C
或 P A B
得形式表示所要做的事情(这里 \(A, B, C\) 为整数, 可能 \(A> B\),这样的话需要你交换 \(A\) 和 \(B\))。
输出格式
对于老师的提问,做出相应的回答。每行一个整数。
样例 #1
样例输入 #1
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
样例输出 #1
2
1
暴力思路:建30棵线段树 维护每个区间上的颜色
以后可以这种方法“骗分”!!!
我是采用维护 maxx 如果 tr[id][p].maxx>0说明id这种颜色有
注意一个点 我们bj是 -1 0 1 -1代表标记清除! 由于 这道题 0/1 有特殊含义 所以不能像普通懒标记那样 用 0来代表清除
至于最后一个点嘛 这种写法就是 用空间换取了简便写法 要卡过去的话要将 tr中维护的l r 在每个函数中带上 也就是 只有 tr[id][p].maxx 和 tr[id][p].bj 这种才能将空间卡过去
当然 已经足够了(本来就没强求AC)
#include<bits/stdc++.h>
using namespace std;
const int N=6e4+5;
int n,t,o;
struct SegTree {
int l,r,maxx,bj=-1;//-1 0 1
} tr[31][N<<2];
void pushup(int id,int p) {
tr[id][p].maxx=max(tr[id][p<<1].maxx,tr[id][p<<1|1].maxx);
}
void pushdown(int id,int p) {
if(tr[id][p].bj==-1)return ;
tr[id][p<<1].maxx=tr[id][p].bj;
tr[id][p<<1|1].maxx=tr[id][p].bj;
tr[id][p<<1].bj=tr[id][p].bj;
tr[id][p<<1|1].bj=tr[id][p].bj;
tr[id][p].bj=-1;
}
void build(int id,int p,int l,int r,int k) {
tr[id][p].l=l,tr[id][p].r=r;
if(l==r) {
tr[id][p].maxx=k;
return ;
}
int mid=(l+r)>>1;
build(id,p<<1,l,mid,k);
build(id,p<<1|1,mid+1,r,k);
pushup(id,p);
}
void modify(int id,int p,int l,int r,int k) {
if(l<=tr[id][p].l&&r>=tr[id][p].r) {
tr[id][p].bj=k;
tr[id][p].maxx=k;
return ;
}
pushdown(id,p);
int mid=(tr[id][p].l+tr[id][p].r)>>1;
if(l<=mid)modify(id,p<<1,l,r,k);
if(r>mid)modify(id,p<<1|1,l,r,k);
pushup(id,p);
}
int query(int id,int p,int l,int r) {
int maxx=-1;
if(l<=tr[id][p].l&&r>=tr[id][p].r)return tr[id][p].maxx;
pushdown(id,p);
int mid=(tr[id][p].l+tr[id][p].r)>>1;
if(l<=mid)maxx=max(maxx,query(id,p<<1,l,r));
if(r>mid)maxx=max(maxx,query(id,p<<1|1,l,r));
return maxx;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>t>>o;
build(1,1,1,n,1);
for(int i=2; i<=t; i++)build(i,1,1,n,0);
while(o--) {
char op;
int a,b,c;
cin>>op;
if(op=='C') {
cin>>a>>b>>c;
if(a>b)swap(a,b);
modify(c,1,a,b,1);
for(int i=1; i<=t; i++)
if(i!=c)
modify(i,1,a,b,0);
}
if(op=='P') {
cin>>a>>b;
if(a>b)swap(a,b);
int ans=0;
for(int i=1; i<=t; i++)
if(query(i,1,a,b)>0)
ans++;
cout<<ans<<"\n";
}
}
return 0;
}
优化空间AC版
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,t,o;
struct SegTree {
int maxx,bj=-1;//-1 0 1
} tr[31][N<<2];
void pushup(int id,int p) {
tr[id][p].maxx=max(tr[id][p<<1].maxx,tr[id][p<<1|1].maxx);
}
void pushdown(int id,int p) {
if(tr[id][p].bj==-1)return ;
tr[id][p<<1].maxx=tr[id][p].bj;
tr[id][p<<1|1].maxx=tr[id][p].bj;
tr[id][p<<1].bj=tr[id][p].bj;
tr[id][p<<1|1].bj=tr[id][p].bj;
tr[id][p].bj=-1;
}
void build(int id,int p,int l,int r,int k) {
if(l==r) {
tr[id][p].maxx=k;
return ;
}
int mid=(l+r)>>1;
build(id,p<<1,l,mid,k);
build(id,p<<1|1,mid+1,r,k);
pushup(id,p);
}
void modify(int id,int p,int l,int r,int L,int R,int k) {
if(l>R||r<L)return ;
if(L<=l&&R>=r) {
tr[id][p].bj=k;
tr[id][p].maxx=k;
return ;
}
pushdown(id,p);
int mid=(l+r)>>1;
if(L<=mid)modify(id,p<<1,l,mid,L,R,k);
if(R>mid)modify(id,p<<1|1,mid+1,r,L,R,k);
pushup(id,p);
}
int query(int id,int p,int l,int r,int L,int R) {
int maxx=-1;
if(l>R||r<L)return 0;
if(L<=l&&R>=r)return tr[id][p].maxx;
pushdown(id,p);
int mid=(l+r)>>1;
if(L<=mid)maxx=max(maxx,query(id,p<<1,l,mid,L,R));
if(R>mid)maxx=max(maxx,query(id,p<<1|1,mid+1,r,L,R));
return maxx;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n>>t>>o;
build(1,1,1,n,1);
for(int i=2; i<=t; i++)build(i,1,1,n,0);
while(o--) {
char op;
int a,b,c;
cin>>op;
if(op=='C') {
cin>>a>>b>>c;
if(a>b)swap(a,b);
modify(c,1,1,n,a,b,1);
for(int i=1; i<=t; i++)
if(i!=c)
modify(i,1,1,n,a,b,0);
}
if(op=='P') {
cin>>a>>b;
if(a>b)swap(a,b);
int ans=0;
for(int i=1; i<=t; i++)
if(query(i,1,1,n,a,b)>0)
ans++;
cout<<ans<<"\n";
}
}
return 0;
}