hdu5200 Trees(逆向思维+离线处理)

题意描述:

在一条直线上有n棵树,每棵树有一个高度。现在进行查询:给一个高度h,把小于等于h的树砍掉,剩余的树能组成几个块?

块的定义:一个块要包含尽可能多的位置连续的树,而且被包含的树没有被砍掉

解题思路:离线处理

1、逆向思维:砍树的对立面就是长树

(1)如果我们把树的高度和查询高度都按从大到小的顺序排序,初始化直线上没有一棵树存在;

(2)然后从前往后扫描查询,对于当前查询,我们只需要把高于当前查询的树生长出来(vis数组标记即可)

(3)在每颗树生长的同时检测其两边的树是否已经生长,对于不同的情况分类讨论即可

源代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 50010
using namespace std;

struct node{
    int h;
    int index;
};
bool cmp(node a,node b){
    return a.h>b.h;
}
node d[MAXN];///树的高度
node q[MAXN];///查询高度
bool vis[MAXN];///标记树是否已经生长
int ans[MAXN];///每个查询的连通块
int n,m;
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=0;i<n;++i)
        {
            scanf("%d",&d[i].h);
            d[i].index=i;
        }
        sort(d,d+n,cmp);
        for(int i=0;i<m;++i){
            scanf("%d",&q[i].h);
            q[i].index=i;
        }
        sort(q,q+m,cmp);
        int id=0,iq=0;
        int tans=0;
        memset(vis,false,sizeof(vis));
        while(iq<m){
            if(id<n){
                if(q[iq].h>=d[id].h){///没有可以生长的树
                    ans[q[iq].index]=tans;
                    iq++;
                }
                else{
                    for(;id<n&&d[id].h>q[iq].h;++id){
                        int tl=d[id].index-1;
                        int tr=d[id].index+1;
                        if(tl>=0&&tr<n&&vis[tl]&&vis[tr])///如果树两边的树都已经生长,加上这棵树之后构成一个块,由2变为1
                            tans--;
                        ///两边的树如果都还没有生长,则块+1
                        if(tl>=0){
                            if(!vis[tl]){
                                if(tr<n){
                                    if(!vis[tr])
                                        tans++;
                                }
                                else
                                    tans++;
                            }
                        }
                        else{
                            if(tr<n){
                                if(!vis[tr])
                                    tans++;
                            }
                            else
                                tans++;
                        }
                        vis[tl+1]=true;
                    }
                    ans[q[iq].index]=tans;
                }
            }
            else///所有的树已经生长完
            {
                ans[q[iq].index]=tans;
                iq++;
            }
        }
        for(int i=0;i<m;++i)
            printf("%d\n",ans[i]);
    }
    return 0;
}

2、正向思维:

1、我们把树的高度和查询高度从小到大排序,从前往后处理每个查询,初始化直线上的所有树都在

2、对于当前查询,我们只需要把小于等于查询高度的树砍掉即可

3、对于每次砍树,检测其两边的树是否被砍掉,分类讨论即可

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 04:53:48

hdu5200 Trees(逆向思维+离线处理)的相关文章

HDU5200 Trees (离线处理)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5200 题意: 每次去掉高度小于q的树,每次输出剩下的块数. 分析: 我们对高度从高到低进行排序,对要去掉的高度从低到高进行排序. 因此前面去掉的在后面一定会去掉,因可以离线处理,节省时间, 然后需要开一个辅助空间,记录这棵树去没有去掉. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #incl

hdu 5200 Trees [ 排序 离线 2指针 ]

传送门 Trees Accepts: 156 Submissions: 533 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description Today CodeFamer is going to cut trees.There are N trees standing in a line. They are numbered from 1 to N. Th

Hdu 5200 Trees (离线线段树)

题目大意: 校门外栽满了不同高度的树,每一次询问是 如果砍掉所有高度不超过q的树,那么还有多少个连续的块. 思路分析: 记录左连续和   右连续和  用来维护区间的连续块的数量. 即 seg[num] = seg[num<<1]+seg[num<<1|1] ; 如果中间部分连起来  那么减一即可. #include <cstdio> #include <iostream> #include <cstring> #include <algor

BestCoder Round #36 (hdu5200)Strange Class(离线)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Today CodeFamer is going to cut trees.There are N trees standing in a line. They

HDU5200 数据离线处理

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5200 ,数据离线处理. 这是BestCoder Round #36的C题,比赛时自己用线段树做,姿势不够优美,TLE了,后来才想到用离线处理的话很简单. 解法: 先把所有的树的高度和下标都存下来,然后按照高度进行排序:接下来把所有询问都先存下来,按照询问的高度进行排序.对于当前的查询h,在树中删除比h小的树木,假设删除的树的下标为p,则查看当前p+1和p-1位置的树木是否删去,如果两个位置都在,则+

[hdu5200]离线+标记

思路:按顺序处理,新建一堆然后向左右合并,不过巧妙地用了标记数组来记录和统计答案. 1 #pragma comment(linker, "/STACK:10240000,10240000") 2 3 #include <iostream> 4 #include <cstdio> 5 #include <algorithm> 6 #include <cstdlib> 7 #include <cstring> 8 #include

【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)

Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

集成Android免费语音合成功能(在线、离线、离在线融合)

集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(离线)集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(离在线融合) 转眼间,大半年没写文章了,没什么理由,就是人变懒了.囧~ 看标题,其实大家都被骗了,有这一篇文章还不够,我其实是打算分3篇文章来写的,如果合在一章里面就太长了,不过现在这个标题党横行的网络世界,我也被污染了,哈.那么为什么要分3篇文章来讲呢?看标题也能猜到了,就是在线.离线.离在线融合这3种语音合成方式,我将分别使

正则表达式中的逆向思维

人们的正常思维都是顺向的,那么逆向思维呢,特别是初学正则表达式的同学们,好不容易掌握了正则表达式的用法,再突然要你用逆向思维做题,会有很多不适应: 这里拿三道题,来做简单介绍: 1.经典例题取IP: [[email protected] ~]# ifconfig eth0|sed -nr '2s#^[^0-9]+(.*)[a-Z]{5,}.*#\1#gp' 10.0.0.200 2.调换/etc/passwd中最后一列和第一列的位置: [[email protected] ~]# head /p