[kuangbin帶你飛]專題七 線段樹(poj-2528,區間染色+離線)

D - Mayor’s posters POJ - 2528

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

題意:

給你一個區間,每次都對一個子區間染色,顏色會覆蓋。
問:最後有多少種顏色。

思路:

  1. 數據很大,直接線段樹會超。所以先離線
  2. 離線後,就是線段樹的常規操作了。之後就讀一個區間就把這個區間染色。
  3. pushdown時把當前區間的顏色傳遞給【a,mid】和【mid,b】。而【a,b】的顏色置爲0,(一次次的pushdown,總會到單點,方便dfs考察時要考察單點的顏色)
  4. dfs統計所有的單點有多少種顏色。

反思

  1. 離線時的
	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);
        }
  1. 線段樹的基本操作時,要注意
  2. 這題離線時,其實要把一個區間縮成一個點,但是數據弱,都過了。縮點操作詳見,矩形的並掃描線。

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章