HDU 5200 Tree (離線並查集)

_TCgogogo_發表於2015-09-19

Trees

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1146    Accepted Submission(s): 363

Problem Description
Today CodeFamer is going to cut trees.There areN trees standing in a line. They are numbered from 1 to N. The tree numbered i has height hi. We say that two uncutted trees whose numbers are x and y are in the same block if and only if they are fitting in one of blow rules:

1)x+1=y or y+1=x;

2)there exists an uncutted tree which is numbered z, and x is in the same block with z, while y is also in the same block with z.

Now CodeFamer want to cut some trees whose height is not larger than some value, after those trees are cut, how many tree blocks are there?


Input
Multi test cases (about 15).

For each case, first line contains two integers N and Q separated by exactly one space, N indicates there are N trees, Q indicates there are Q queries.

In the following N lines, there will appear h[1],h[2],h[3],,h[N] which indicates the height of the trees.

In the following Q lines, there will appear q[1],q[2],q[3],,q[Q] which indicates CodeFamer’s queries.

Please process to the end of file.

[Technical Specification]

1N,Q50000

0h[i]1000000000(109)

0q[i]1000000000(109)
 
Output
For each q[i], output the number of tree block after CodeFamer cut the trees whose height are not larger thanq[i].

Sample Input
3 2 5 2 3 6 2
 
Sample Output
0 2
Hint
In this test case, there are 3 trees whose heights are 5 2 3. For the query 6, if CodeFamer cuts the tree whose height is not large than 6, the height form of left trees are -1 -1 -1(-1 means this tree was cut). Thus there is 0 block. For the query 2, if CodeFamer cuts the tree whose height is not large than 2, the height form of left trees are 5 -1 3(-1 means this tree was cut). Thus there are 2 blocks.
 
Source

BestCoder Round #36 ($)


題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5200


題目大意:有n棵樹,每棵高度位hi,q個詢問,每次砍掉高度不大於qi的樹,每個詢問後輸出當前有樹的區域被分成了幾塊


題目分析:典型的離線並查集,把沒被砍掉的樹併到一起,查詢的高度從大到小排序,因為如果qi > qj的話,qi時被合併的樹在qj時顯然還是並在一起的,注意這裡還需要對樹高從大到小排序,這是一個防止超時的優化,即如果當前的樹高度比qi小了,那就可以退出了,因為後面的樹肯定都要被砍掉,每列舉一棵樹cnt就要加1,每合併一次,cnt要減1,最後用id記錄詢問編號

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAX = 1e5 + 5;
int ans[MAX], fa[MAX], h[MAX];
int n, Q, cnt;

struct DATA
{
    int id, h;
}q[MAX], s[MAX];

bool cmp(DATA a, DATA b)
{
    return a.h > b.h;
}

void UF_set()
{
    for(int i = 0; i <= n; i++)
        fa[i] = i;
}

int Find(int x)
{
    return x == fa[x] ? x : fa[x] = Find(fa[x]);
}

void Union(int a, int b)
{
    int r1 = Find(a);
    int r2 = Find(b);
    if(r1 != r2)
    {
        fa[r1] = r2;
        cnt --;
    }
}

int main()
{
    while(scanf("%d %d", &n, &Q) != EOF)
    {
        cnt = 0;
        UF_set();
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &h[i]);
            s[i].h = h[i];
            s[i].id = i;
        }
        h[0] = h[n + 1] = 0;
        for(int i = 1; i <= Q; i++)
        {
            scanf("%d", &q[i].h);
            q[i].id = i;
        }
        sort(s + 1, s + n + 1, cmp);
        sort(q + 1, q + Q + 1, cmp);
        int j = 1;
        for(int i = 1; i <= Q; i++)
        {
            while(j <= n && h[s[j].id] > q[i].h)
            {
                cnt ++;
                if(h[s[j].id - 1] > q[i].h)
                    Union(s[j].id - 1, s[j].id);
                if(h[s[j].id + 1] > q[i].h)
                    Union(s[j].id + 1, s[j].id);
                j ++;
            }
            ans[q[i].id] = cnt;
        }
        for(int i = 1; i <= Q; i++)
            printf("%d\n", ans[i]);
    }
}



相關文章