[HDU2969]Skyscrapers

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description

In a seaside village, there is an avenue of skyscrapers. Each skyscrapers is 100m wide and has certain height. Due to very high price of parcels, any two consecutive skyscrapers are adjacent.

The avenue lies close to the beach so the street is exactly at the sea level.

Unfortunately, this year, due to the global warming, the sea level started to increase by one meter each day. If the skyscraper height is no greater than the current sea level, it is considered flooded.

A region is a maximal set of non-flooded, adjacent skyscrapers. This term is of particular importance, as it is suficient to deliver goods (like current, carrots or cabbages) to any single skyscraper in each region.

Hence, the city major wants to know how many regions there will be in the hard days that come. An example of an avenue with 5 5 5 skyscrapers after 2 2 2 days is given below.

Input
The input contains several test cases. The first line contains an integer t ( t &lt; = 15 ) t (t &lt;= 15) t(t<=15) denoting the number of test cases. Then t test cases follow. Each of them begins with a line containing two numbers n n n and d ( 1 &lt; = n , d &lt; = 1 0 6 ) d (1 &lt;= n, d &lt;=10^6) d(1<=n,d<=106), n n n is the number of skyscrapers and d d d is the number of days which the major wants
to query.

Skyscrapers are numbered from left to right. The next line contains n n n integers h 1 , h 2 , . . . , h n h_1,h_2,..., h_n h1,h2,...,hn where 1 &lt; = h i &lt; = 1 0 9 1 &lt;= h_i &lt;= 10^9 1<=hi<=109 is the height of skyscraper i i i. The third line of a single test case contains d d d numbers t j tj tj such that 0 &lt; = t 1 &lt; t 2 &lt; . . . &lt; t d − 1 &lt; t d &lt; = 1 0 9 0 &lt;= t_1 &lt; t_2 &lt; ... &lt; t_{d-1} &lt; t_d &lt;=10^9 0<=t1<t2<...<td1<td<=109.

Output
For each test case output d d d numbers r 1 , r 2 , . . . , r d r_1,r_2,...,r_d r1,r2,...,rd, where rj is the number of regions on day t j t_j tj .

Sample Input

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

Sample Output

1 1 0
1 2 1

Source
Central European Programming Contest 2008

题意:
n n n个楼,高度是 h 1 h_1 h1 h n h_n hn d d d次询问,每次询问一个数字 t i t_i ti,询问的 t i t_i ti的值递增,问将所有的高度低于或者等于 t i t_i ti的楼去掉之后,剩下的region有多少个?region:一段连续存在的楼房算作一个region。

题解:
先将楼房按照高度从高到低排序,然后倒着处理询问,每次询问等于添加若干座楼房之后还有多少个region,这个可以用并查集解决。f[i]表示当前第i座楼房处于哪个region里,然后每个region会记录一个l,r表示这个region的控制的区间[L,R],然后每次有楼房出现的时候就判断其两端是否有连接这某个region然后合并即可。
坑点,卡内存,然后输出的时候每一行结尾要有一个空格。

#include<bits/stdc++.h>
#define LiangJiaJun main
using namespace std;
int n,d;
short vis[1000004];
int ans[1000004],f[1000004],wp[1000004];
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
struct Lip{
    int l,r;
}reg[1000004];
struct Ds{
    int h,sit;
}a[1000004];
inline bool dex(Ds A,Ds B){
    return A.h<B.h;
}
int res;
void uni(int x,int y){
     int p=Find(x),q=Find(y);
     if(p!=q){
        f[p]=q;
        reg[q].l=min(reg[q].l,reg[p].l);
        reg[q].r=max(reg[q].r,reg[p].r);
     }
}
void exist(int x){
     vis[x]=0;
     if(vis[x-1]&&vis[x+1])res++;
     else if((!vis[x-1])&&vis[x+1])uni(x-1,x);
     else if(vis[x-1]&&(!vis[x+1]))uni(x,x+1);
     else{
        res--;
        uni(x-1,x);
        uni(x,x+1);
     }
}
int w33ha(){
    scanf("%d%d",&n,&d);
    vis[0]=1;vis[n+1]=1;
    for(int i=1;i<=n;i++){
        vis[i]=0;
        f[i]=i;
        reg[i].l=i;
        reg[i].r=i;
        scanf("%d",&a[i].h);
        a[i].sit=i;
    }
    sort(a+1,a+n+1,dex);
    int now=1;
    for(int i=1;i<=d;i++){
        scanf("%d",&wp[i]);
        while(now<=n&&a[now].h<=wp[i]){
            vis[now]=1;
            now++;
        }
    }
    res=0;
    now=n;
    for(int i=d;i>=1;i--){
        while(0<now&&wp[i]<a[now].h){
            exist(a[now].sit);
            now--;
        }
        ans[i]=res;
    }
    for(int i=1;i<=d;i++){
        printf("%d ",ans[i]);
    }
    puts("");
    return 0;
}
int LiangJiaJun(){
    int T;scanf("%d",&T);
    while(T--)w33ha();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值