1. 程式人生 > >D - Mayor's posters (線段樹 + 離散化)

D - Mayor's posters (線段樹 + 離散化)

滴答滴答---題目連結

The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules: 

  • Every candidate can place exactly one poster on the wall. 
  • All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown). 
  • The wall is divided into segments and the width of each segment is one byte. 
  • Each poster must completely cover a contiguous number of wall segments.


They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections. 
Your task is to find the number of visible posters when all the posters are placed given the information about posters' size, their place and order of placement on the electoral wall. 

Input

The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers l i and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= l i <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered l i, l i+1 ,... , ri.

Output

For each input data set print the number of visible posters after all the posters are placed. 

The picture below illustrates the case of the sample input. 

Sample Input

1
5
1 4
2 6
8 10
3 4
7 10

Sample Output

4

1.先把每條線段的單獨存下來,同時把每個端點的值存在另一個數組裡,在此把圖放上

        for(int i = 1; i <= n; ++ i)
        {
            cin >> li[i] >> ri[i];
            x[cnt++] = li[i];
            x[cnt++] = ri[i];
        }
2.來一發排序,sort即可,然後處理一下相鄰資料的差超過1的情況。先解釋一下為什麼,線段樹是以點的形式儲存了線段,所以難免會有侷限,比如區間[1, 4]和[5, 6], 線上段數裡面其實是相連線的,也就是說中間沒有空隙(注意!!!),按照普通的離散化,兩個不連續的數離散化之後會是連續的數,比如[1, 4], [2, 8], [7, 10]這三條線段,離散後:[1, 3], [2, 5], [4, 6], 然後算算離散前後的結果,一個是3, 一個是2,所以說就要把相差超過1的資料的特點體現出來,使得其之間有空隙。方法就是在這兩個數中間再加一個數。就是x[i - 1]++這個操作了,最後再來發sort就ok了

        sort(x + 1, x + cnt);
        int m = cnt;
        for(int i = 2; i < cnt; ++ i)
        {
            if(x[i] - x[i - 1] > 1)
            {
                x[m++] = x[i - 1]++;
            }
        }
        sort(x + 1, x + m);
3.然後把陣列中重複的元素去掉,因為接下來我們要用二分查詢來確定每條線段的標號,去重才能保證標號唯一。

        int top = 2;
        y[1] = x[1];
        for(int i = 2; i < m; ++ i)
        {
            if(x[i] != x[i - 1])
            {
                y[top++] = x[i];
            }
        }
4.下來就是通過二分查詢把每條線段離散後的範圍和標號對應起來,進行區間更新。

 for(int i = 1; i <= n; ++ i)
 {
     int L = Bin(1, top - 1, li[i]);
     int R = Bin(1, top - 1, ri[i]);
     Update(L, R, i, 1, top - 1, 1);
 }


另外附上二分查詢的函式

 inline int Bin(int l, int r, int x)
{
    int m;
    while(l < r)
    {
        m = (l + r) / 2;
        if(y[m] == x)
            return m;
        else if(y[m] > x)
            r = m - 1;
        else
            l = m + 1;
    }
    return l;
}
最後再查詢一波就好了

下面上完整程式碼:

再解釋一下我的線段樹,我用-1代表此區間沒有顏色或者不是純色的情況(反正這兩種情況都差不多,不能直接統計)

#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=100001;
int tree[8*N],li[N*4],ri[N*4];
int x[N*4],y[N*4],sum;
int vis[N*4];
int bin(int l,int r,int x)
{

    int m;
    while(l<r)
    {
        m=(l+r)/2;
        if(y[m]==x)
            return m;
        else if(y[m]>x)
            r=m-1;
        else
            l=m+1;
    }
    return l;
}
void updata(int a,int b,int op,int l,int r,int rt)
{
    if(l>=a&&b>=r)
    {
        tree[rt]=op;
        return;
    }
    if(tree[rt]!=-1)
    {
        int ans=tree[rt];
        tree[rt*2]=ans;
        tree[rt*2+1]=ans;
        tree[rt]=-1;
    }
    int m=(l+r)>>1;
    if(m>=a)
        updata(a,b,op,l,m,rt<<1);
    if(m<b)
        updata(a,b,op,m+1,r,rt<<1|1);
}
void query(int l,int r,int rt)
{
    if(tree[rt]!=-1)
    {
        if(!vis[tree[rt]])
        {
            vis[tree[rt]]=1;
            sum++;
        }
        return;
    }
    if(l==r)
        return;
    int m=(l+r)/2;
    query(l,m,rt<<1);
    query(m+1,r,rt<<1|1);

}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {

        scanf("%d",&n);
        memset(vis,0,sizeof(vis));
        memset(tree,-1,sizeof(tree));
        int ans=1;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&li[i],&ri[i]);
            x[ans++]=li[i];
            x[ans++]=ri[i];

        }
        sort(x+1,x+ans);
        int m=ans;
        for(int i=2; i<ans; i++)
        {
            if(x[i]-x[i-1]>1)
                x[m++]=x[i-1]++;

        }
        sort(x+1,x+m);
        int top=2;
        y[1]=x[1];
        for(int i=2; i<m; i++)
        {
            if(x[i]!=x[i-1])
                y[top++]=x[i];

        }
        for(int i=1; i<=n; i++)
        {
            int l=bin(1,top-1,li[i]);
            int r=bin(1,top-1,ri[i]);
            updata(l,r,i,1,top-1,1);

        }
        sum=0;
        query(1,top-1,1);
        printf("%d\n",sum);

    }

    return 0;
}