有一个纸带·,每次区间染色,同一个地方后染的颜色覆盖先染的,求最后纸带上颜色种类数。
咦,这不是线段树吗?
咦,倒过来做好像很方便啊?
咦,离散化有坑?
区间涂色,若该颜色所在区间均被染色,则该颜色按原顺序操作后会被后面的颜色覆盖
注意离散化
本来三个颜色3-8,2-5,7-9,最后6号点上颜色是1
离散化后为2-5,1-3,4-6,颜色1就被“吃”掉了
怎么解决?自(kan)行(dai)思(ma)考(ba)
#include<bits/stdc++.h>
#define LEN 1000005
using namespace std;
inline int getint(){
int x=0,p=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')p=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^'0');
c=getchar();
}
return x*p;
}
inline void putint(int x){
if(x<0){
putchar('-');
x=-x;
}
static int buf[30];
int tot=0;
do{
buf[tot++]=x%10;
x/=10;
}while(x);
while(tot)putchar(buf[--tot]+'0');
}
int a[LEN],b[LEN],x[LEN<<3];
bool seg[(LEN<<4)+1],tag[(LEN<<4)+1];
inline void updata(int k){
seg[k]=seg[k<<1]&&seg[k<<1|1];
}
inline void change(int k){
seg[k]=tag[k]=1;
}
inline void pushdown(int k){
if(tag[k]){
change(k<<1);
change(k<<1|1);
tag[k]=0;
}
}
void modify(int k,int l,int r,int s,int t){
if(seg[k])return;
pushdown(k);
if(s<=l&&r<=t){
change(k);
return;
}
int mid=l+r>>1;
if(s<=mid)modify(k<<1,l,mid,s,t);
if(mid<t)modify(k<<1|1,mid+1,r,s,t);
updata(k);
}
bool query(int k,int l,int r,int s,int t){
if(seg[k])return true;
pushdown(k);
if(s<=l&&r<=t){
return seg[k];
}
int mid=l+r>>1;
bool ans=1;
if(s<=mid)ans=ans&&query(k<<1,l,mid,s,t);
if(mid<t)ans=ans&&query(k<<1|1,mid+1,r,s,t);
updata(k);
return ans;
}
int main(){
int n=getint();
for(int i=1;i<=n;++i){
a[i]=getint()+1,b[i]=getint();
x[i*2-1]=a[i],x[i*2]=b[i];
}
int tot=n*2;
for(int i=1;i<=n;++i){
x[++tot]=b[i]+1;
}
sort(x+1,x+tot+1);
tot=unique(x+1,x+tot+1)-x;
for(int i=1;i<=n;++i){
a[i]=lower_bound(x+1,x+tot,a[i])-x;
b[i]=lower_bound(x+1,x+tot,b[i])-x;
}
int ans=0;
for(int i=n;i>=1;--i){
if(!query(1,1,tot,a[i],b[i])){
++ans;
modify(1,1,tot,a[i],b[i]);
}
}
cout<<ans<<endl;
return 0;
}
咦,正解竟然是并查集!
我们将区间覆盖用并查集优化,维护当前颜色最右端,合并时将一段颜色的最右端与相邻格子合并即可
#include<bits/stdc++.h>
#define LEN 2000006
using namespace std;
inline int getint(){
int x=0,p=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')p=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^'0');
c=getchar();
}
return x*p;
}
int ans=0;
int a[LEN],b[LEN],x[LEN];
int fa[LEN];
inline int getfa(int x){
return fa[x]=(fa[x]==x?x:getfa(fa[x]));
}
inline int merge(int u,int v){
u=getfa(u),v=getfa(v);
return fa[u]=v;
}
inline void modify(int l,int r){
if(getfa(l)>=r)return;
++ans;
for(int i=getfa(l);i<r;i=merge(i,i+1));
}
int main(){
int n=getint();
for(int i=1;i<=n;++i){
a[i]=getint(),b[i]=getint();
x[i*2-1]=a[i],x[i*2]=b[i];
}
int tot=n*2;
sort(x+1,x+tot+1);
tot=unique(x+1,x+tot+1)-x;
for(int i=1;i<=n;++i){
a[i]=lower_bound(x+1,x+tot,a[i])-x;
b[i]=lower_bound(x+1,x+tot,b[i])-x;
}
for(int i=1;i<=tot;++i){
fa[i]=i;
}
for(int i=n;i>=1;--i){
modify(a[i],b[i]);
}
cout<<ans<<endl;
return 0;
}