ZOJ 1610 Count the Colors [ 線段樹 + 區間染色 ]

題目鏈接:

POJ - 2528 Count the Colors

題意概括:

按順序給出一些線段,後出現的線段會覆蓋前出現線段的重疊部分。求剩下線段中,有哪些顏色,同時求出每種顏色線段數量

數據範圍:

1 <= n <= 8000

0 <= x1 , x2 , c <= 8000

題解分析:

區間更新的問題,很明顯應該用線段樹來做,但是有很多細節要注意

origin數組維護的原數據是線段的顏色,並且用右節點的下標作爲它的下標

如:下標爲 0,1 兩個節點的線段,下標是 1

線段樹維護的值是區間的顏色:

  • 如果區間內的所有線段顏色相同,則該區間的顏色就是這個顏色
  • 反之,該區間的顏色編號就是 INF,表示區間顏色不一致

這裏需要遍歷到每個點,也就是最下層的位置。按遍歷的順序可以知道,我們可以從左到右依次遍歷每條單位線段

定義一個 last變量 記錄上一條單位線段的顏色,防止同一條線段重複計數

AC代碼:

#include <stdio.h>
#include <memory.h>
using namespace std;
const int MAXN = 8e3 + 10;
const int INF = 0x3f3f3f3f;
int origin[MAXN], tree[MAXN<<2], lazy[MAXN<<2], ans[MAXN], last = INF;

void pushup(int p) {
    if (tree[p << 1] == tree[p << 1 | 1])
        tree[p] = tree[p << 1];
    else
        tree[p] = INF;
}

void pushdown(int p, int l, int r) {
    if (lazy[p] != INF) {
        lazy[p << 1] = lazy[p];
        lazy[p << 1 | 1] = lazy[p];
        tree[p << 1] = lazy[p];  //左右兒子結點均按照需要加的值總和更新結點信息
        tree[p << 1 | 1] = lazy[p];
        lazy[p] = INF;
    }
}

void build(int p, int l, int r) {
    if (l == r) {
        tree[p] = origin[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pushup(p);
}

void update(int p, int l, int r, int ql, int qr, int v) {   //區間更新
    if (ql <= l && r <= qr) {       //當前區間在更新區間內
        tree[p] = v;
        lazy[p] = v;
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(p, l, r);
    if (ql <= mid)  update(p << 1, l, mid, ql, qr, v);
    if (qr > mid)  update(p << 1 | 1, mid + 1, r, ql, qr, v);
    pushup(p);
}


void query(int p, int l, int r, int ql, int qr) {
    if (l == r) {
    if (tree[p] != INF && tree[p] != last)
            ans[tree[p]] ++;
        last = tree[p];
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(p, l, r);        //有區間更新時才需要
    
    query(p << 1, l, mid, ql, qr);
    query(p << 1 | 1, mid + 1, r, ql, qr);    //分塊切割出有效的部分(已忽略無效部分)
}

int main () {

    int n;
    while(scanf("%d", &n)!= EOF) {
    int i, j, c;
        memset(lazy, INF, sizeof(lazy));
        memset(ans, 0, sizeof(ans));
        last = INF;
        
        for (int i = 1; i <= 8001; i++)
            origin[i] = INF;
        build(1, 1, 8001);
        
        while(n--) {
            scanf("%d%d%d", &i, &j, &c);
                update(1, 1, 8001, i + 1, j, c);
            }
        query(1, 1, 8001, 1, 8001);
        for (int i = 0; i <= 8000; i ++)
            if (ans[i]) printf("%d %d\n", i, ans[i]);
         putchar('\n');
        }
    }

 

                                                    Count the Colors

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. 

Your task is counting the segments of different colors you can see at last.

Input

The first line of each data set contains exactly one integer n, 1 <= n <= 8000, equal to the number of colored segments.

Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:  x1 x2 c

x1 and x2 indicate the left endpoint and right endpoint of the segment, c indicates the color of the segment.

All the numbers are in the range [0, 8000], and they are all integers.

Input may contain several data set, process to the end of file.

Output

Each line of the output should contain a color index that can be seen from the top, following the count of the segments of this color, they should be printed according to the color index.

If some color can't be seen, you shouldn't print it.

Print a blank line after every dataset.

Sample Input

5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1

Sample Output

1 1
2 1
3 1

1 1

0 2
1 1

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章