D - Mayor’s posters POJ - 2528
題意:
給你一個區間,每次都對一個子區間染色,顏色會覆蓋。
問:最後有多少種顏色。
思路:
- 數據很大,直接線段樹會超。所以先離線
- 離線後,就是線段樹的常規操作了。之後就讀一個區間就把這個區間染色。
- pushdown時把當前區間的顏色傳遞給【a,mid】和【mid,b】。而【a,b】的顏色置爲0,(一次次的pushdown,總會到單點,方便dfs考察時要考察單點的顏色)
- dfs統計所有的單點有多少種顏色。
反思:
- 離線時的
For(i,1,n)
{
int l,r;
scanf("%d%d", &l,&r);
q[i].l=a[++cnt]=l;
q[i].r=a[++cnt]=r;
}
sort(a+1,a+1+cnt);
m=unique(a+1,a+1+cnt)-(a+1);
//這裏要減去一個1,因爲unique返回的是開始出現重複元素時的下標。
build(1,1,m);
For(i,1,n)
{
//cout<<q[i].l<<' '<<q[i].r<<endl;
int x=lower_bound(a+1,a+1+m,q[i].l)-a;
//這裏不用減去1,因爲是返回的第幾個,注意注意
int y=lower_bound(a+1,a+1+m,q[i].r)-a;
// cout<<x<<' '<<y<<endl;
update(1,x,y,i);
}
- 線段樹的基本操作時,要注意
- 這題離線時,其實要把一個區間縮成一個點,但是數據弱,都過了。縮點操作詳見,矩形的並掃描線。
AC
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
typedef long long ll;
const int maxn=2e4+10;
int a[maxn],vis[maxn];
int n,m,cnt,ans;
struct query
{
int l,r,id;
} q[maxn];
struct tree
{
int l,r;
ll pre;
} t[maxn<<2];
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r)
{
t[p].pre=0;
return ;
}
int mid=t[p].l+(t[p].r-t[p].l)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p].pre=0;
}
void pushdown(int p)
{
t[p<<1].pre=t[p].pre;
t[p<<1|1].pre=t[p].pre;
t[p].pre=0;//把當前區間的顏色置爲0,是爲了後面的dfs訪問單點時好操作,看有多少個顏色就看有多少個點即可。
}
void update(int p, int x,int y, int z)
{
if(x<=t[p].l && y>=t[p].r)
{
t[p].pre=z;
return ;
}
if(t[p].pre)pushdown(p);
int mid=t[p].l+(t[p].r-t[p].l)/2;
if(x<=mid)update(p<<1,x,y,z);
if(y>mid)update(p<<1|1,x,y,z);
}
void dfs(int p, int x, int y)
{
if(!vis[t[p].pre]&&t[p].pre)
{
ans++;
vis[t[p].pre]=1;
return ;
}
if(x>=y)return ;
if(t[p].pre)pushdown(p);
int mid=t[p].l+(t[p].r-t[p].l)/2;
dfs(p<<1,x,mid);
dfs(p<<1|1,mid+1,y);
return;
}
int main()
{
int time;
scanf("%d", &time);
while(time--)
{
mst(vis,0);mst(t,0);cnt=0;ans=0;
scanf("%d", &n);
For(i,1,n)
{
int l,r;
scanf("%d%d", &l,&r);
q[i].l=a[++cnt]=l;
q[i].r=a[++cnt]=r;
}
sort(a+1,a+1+cnt);
m=unique(a+1,a+1+cnt)-(a+1);
//這裏要減去一個1,因爲unique返回的是開始出現重複元素時的下標。
build(1,1,m);
For(i,1,n)
{
//cout<<q[i].l<<' '<<q[i].r<<endl;
int x=lower_bound(a+1,a+1+m,q[i].l)-a;
//這裏不用減去1,因爲是返回的第幾個,注意注意
int y=lower_bound(a+1,a+1+m,q[i].r)-a;
// cout<<x<<' '<<y<<endl;
update(1,x,y,i);
}
dfs(1,1,m);
printf("%d\n",ans);
}
return 0;
}