[Noip模拟题]砍树

来源:互联网 发布:电脑怎么用手机网络 编辑:程序博客网 时间:2024/05/28 15:06

Description
小A在一条水平的马路上种了n棵树,过了几年树都长高大了,每棵树都可以看作是一条长度为ai的竖线段。由于有的树过于高大,挡住了其他的树,使得另外一些树得不到阳光。如果有两棵树i,ji顶端与j底端连线的倾角大于45度,我们就定义为i挡住了j。现在小A希望将一些树砍低,使得不存在挡住的情况。他想知道总共最少需要砍掉多少长度,请你来帮他计算一下。注意,如果同一位置有两棵树德话,根据题意,我们只能将这两棵树都砍成高度为0才能保证它们不相互挡住,但是高度为0并不代表这棵树不存在。

Input
第一行一个正整数n,表示有n棵树。
接下来n行,每行两个正整数pi,ai,表示一棵树的位置和高度。
n<=1000000<=pi,ai<=10000

Output
输出一个数,表示最少砍断多少长度。

Sample Input
3
0 2
1 2
3 3

Sample Output
3

HINT

思路
一棵树i能被另一棵树j挡住,当且仅当abs(pipj)<=aj。由于答案只与一个位置是否有树和这棵树的高度有关,而不与树的序号有关,因此,可以记录每个位置的树的高度,如果有两棵树在同一个位置,那么将这一个位置的树的高度变为0,将这两棵树的高度都计入答案。枚举时就寻找是否有满足上面条件的树,处理一下计入答案。这道题就完美的被解决了。

代码

#include <cstdio>#include <cstring>#include <algorithm>const int maxn=10000;int h[maxn+10],n,ans;int main(){    memset(h,255,sizeof h);    scanf("%d",&n);    for(int i=1; i<=n; i++)    {        int a,b;        scanf("%d%d",&a,&b);        if(h[a]!=-1)        {            ans+=h[a]+b;            h[a]=0;        }        else        {            h[a]=b;        }    }    for(int i=0; i<=maxn; i++)    {        int r=h[i];        if(h[i]!=-1)        {            for(int j=std::max(i-h[i],0); j<=std::min(i+h[i],maxn); j++)            {                if((h[j]!=-1)&&(j!=i))                {                    r=std::min(r,abs(j-i));                }            }        }        ans+=h[i]-r;    }    printf("%d\n",ans);    return 0;}
原创粉丝点击