PKU 2528 Mayor's posters
題目鏈接:http://poj.org/problem?id=2528


/**//*
題意:
給定N(N <= 10000)塊木板,依次層疊,問最后能從上方俯視的木板的數量。


解法:
線段樹(染色問題)

思路:
這題是pku 2777的簡化版,木板的數量最多10000種,每個結點都保存下來
似乎有點力不從心,但是因為插入是多次,而詢問只有一次,所以我們只要保證
插入是O(logn)的,而詢問可以O(n),這樣問題就變得簡單許多,線段樹結點保存
一個Cover域,初始化為0,表示是0號木板(輸入數據的木板編號從1開始),每
次插入時只更新到完全覆蓋的區間,如果當前結點的左右兒子的木板顏色不同,
那么它的Cover域就是-1,否則是木板的下標。詢問的時候如果遇到Cover域為-1
的結點則遞歸它的子結點,否則統計。
*/

#include <iostream>
#include <algorithm>
using namespace std;

#define maxn 100010

int tmp[maxn], tmpsize;
int bin[maxn], size;


struct Interval
{
int l, r;
}I[maxn];


struct Tree
{
int nCover;
int son[2];


void clear()
{
son[0] = son[1] = -1;
nCover = 0;
}
}T[ maxn*4 ];
int root, tot = 0;


int GetId(int& root)
{

if(root == -1)
{
root = tot++;
T[root].clear();
}
return root;
}


void Discretization()
{
sort(tmp, tmp + tmpsize);
bin[ size = 1 ] = tmp[0];
int i;

for(i = 1; i < tmpsize; i++)
{
if(tmp[i] != tmp[i-1])
bin[ ++size ] = tmp[i];
}
}


int Binary(int v)
{
int l = 1;
int r = size;

while(l <= r)
{
int m = (l + r) >> 1;
if(bin[m] == v)
return m;

if(v > bin[m])
{
l = m + 1;
}else
r = m - 1;
}
}

int hash[ maxn ], Case;


void Insert(int& root, int nl, int nr, int l, int r, int val)
{
if(nl > r || nr < l)
return ;

GetId(root);

if(nl <= l && r <= nr)
{
T[root].nCover = val;
return ;
}


if(T[root].nCover != -1)
{
int i;

for(i = 0; i < 2; i++)
{
int idx = GetId(T[root].son[i]);
T[idx].nCover = T[root].nCover;
}
T[root].nCover = -1;
}

int mid = (l + r) >> 1;
Insert(T[root].son[0], nl, nr, l, mid, val);
Insert(T[root].son[1], nl, nr, mid+1, r, val);
}


void Query(int root, int l, int r)
{
if(root == -1)
return ;

if(T[root].nCover != -1)
{
hash[ T[root].nCover ] = Case;
return ;
}
int mid = (l + r) >> 1;
Query(T[root].son[0], l, mid);
Query(T[root].son[1], mid+1, r);
}


int main()
{
int t, i;
int n;
scanf("%d", &t);

while(t--)
{
Case ++;
tmpsize = 0;
scanf("%d", &n);

for(i = 0; i < n; i++)
{
scanf("%d %d", &I[i].l, &I[i].r);
tmp[ tmpsize ++ ] = I[i].l;
tmp[ tmpsize ++ ] = I[i].r;
}
Discretization();
root = -1;
tot = 0;

for(i = 0; i < n; i++)
{
I[i].l = Binary(I[i].l);
I[i].r = Binary(I[i].r);
//printf("<%d %d>\n", I[i].l, I[i].r);
Insert(root, I[i].l, I[i].r, 1, size, i+1);
}
int nCount = 0;
Query(root, 1, size);

for(i = 1; i <= size; i++)
{
if(hash[i] == Case)
nCount ++;
}
printf("%d\n", nCount);
}
return 0;
}


/**//*
題意:
給定N(N <= 10000)塊木板,依次層疊,問最后能從上方俯視的木板的數量。

解法:
線段樹(染色問題)
思路:
這題是pku 2777的簡化版,木板的數量最多10000種,每個結點都保存下來
似乎有點力不從心,但是因為插入是多次,而詢問只有一次,所以我們只要保證
插入是O(logn)的,而詢問可以O(n),這樣問題就變得簡單許多,線段樹結點保存
一個Cover域,初始化為0,表示是0號木板(輸入數據的木板編號從1開始),每
次插入時只更新到完全覆蓋的區間,如果當前結點的左右兒子的木板顏色不同,
那么它的Cover域就是-1,否則是木板的下標。詢問的時候如果遇到Cover域為-1
的結點則遞歸它的子結點,否則統計。
*/
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100010
int tmp[maxn], tmpsize;
int bin[maxn], size;

struct Interval
{
int l, r;
}I[maxn];

struct Tree
{
int nCover;
int son[2];

void clear()
{
son[0] = son[1] = -1;
nCover = 0;
}
}T[ maxn*4 ];
int root, tot = 0;

int GetId(int& root)
{
if(root == -1)
{
root = tot++;
T[root].clear();
}
return root;
}

void Discretization()
{
sort(tmp, tmp + tmpsize);
bin[ size = 1 ] = tmp[0];
int i;
for(i = 1; i < tmpsize; i++)
{
if(tmp[i] != tmp[i-1])
bin[ ++size ] = tmp[i];
}
}

int Binary(int v)
{
int l = 1;
int r = size;
while(l <= r)
{
int m = (l + r) >> 1;
if(bin[m] == v)
return m;
if(v > bin[m])
{
l = m + 1;
}else
r = m - 1;
}
}
int hash[ maxn ], Case;

void Insert(int& root, int nl, int nr, int l, int r, int val)
{
if(nl > r || nr < l)
return ;
GetId(root);
if(nl <= l && r <= nr)
{
T[root].nCover = val;
return ;
}

if(T[root].nCover != -1)
{
int i;
for(i = 0; i < 2; i++)
{
int idx = GetId(T[root].son[i]);
T[idx].nCover = T[root].nCover;
}
T[root].nCover = -1;
}
int mid = (l + r) >> 1;
Insert(T[root].son[0], nl, nr, l, mid, val);
Insert(T[root].son[1], nl, nr, mid+1, r, val);
}

void Query(int root, int l, int r)
{
if(root == -1)
return ;
if(T[root].nCover != -1)
{
hash[ T[root].nCover ] = Case;
return ;
}
int mid = (l + r) >> 1;
Query(T[root].son[0], l, mid);
Query(T[root].son[1], mid+1, r);
}

int main()
{
int t, i;
int n;
scanf("%d", &t);
while(t--)
{
Case ++;
tmpsize = 0;
scanf("%d", &n);
for(i = 0; i < n; i++)
{
scanf("%d %d", &I[i].l, &I[i].r);
tmp[ tmpsize ++ ] = I[i].l;
tmp[ tmpsize ++ ] = I[i].r;
}
Discretization();
root = -1;
tot = 0;
for(i = 0; i < n; i++)
{
I[i].l = Binary(I[i].l);
I[i].r = Binary(I[i].r);
//printf("<%d %d>\n", I[i].l, I[i].r);
Insert(root, I[i].l, I[i].r, 1, size, i+1);
}
int nCount = 0;
Query(root, 1, size);
for(i = 1; i <= size; i++)
{
if(hash[i] == Case)
nCount ++;
}
printf("%d\n", nCount);
}
return 0;
}posted on 2011-03-31 21:23 英雄哪里出來 閱讀(1211) 評論(0) 編輯 收藏 引用 所屬分類: 線段樹

