Poj--3263 Tallest Cow(区间修改问题+前缀和思想)

本文介绍了一道关于牛视距的算法题,利用前缀和的思想解决相对身高的计算问题,避免了重复计算,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://vjudge.net/problem/CodeForces-375D#author=634579757

题意:n头牛站一排,两头牛能相互看见,当且仅当它们中间的牛的身高都比它们矮。已知它们中最高的牛的身高是H,并且她是第P头牛,还知道M对关系,每一对关系都指明两头牛Ai和Bi可以相互看见。求每头牛的身高最大可能是多少?

思路:可以用一个数组height表示各头牛的身高,但由于题目给的M个关系只是相对身高关系,所以可以用这个数组表示各个牛的身高的相对关系,最后可以直接已知的那头最高的牛以及它与其他牛的相对身高关系,得出其他牛的身高。

既然height数组表示的是相对身高,那么可以初始化0,然后对于每一个关系,指明Ai和Bi可以相互看见,就把height[Ai+1]~height[Bi-1]的数减去1。为什么是减去1呢? 因为题目要求的是可能的最大身高。最终,其他的牛与最高的那头牛的身高差距就体现在数组height中,换言之,最后第i头牛的身高就等于H+height[i]。

算法实现:

暴力:对于每个关系,都把Ai+1到Bi-1之间的数减去1,这样算法复杂度将是O(MN),复杂度过高。

前缀和思想:额外开一个help数组,对于每对Ai和Bi,也就是Ai+1到Bi-1之间的数都减去1,可以令help[Ai+1]减去1,然后令help[Bi]加上1,这样处理完之后,height[i]就是help的前i个数之和,也就是前缀和。这样的意思是:“减去1”的影响从Ai+1开始,持续到Bi-1,在Bi结束。这个算法把对一个区间的修改操作转化为仅仅对左右两个端点的修改操作,再通过前缀和得到原问题的解。复杂度为O(M+N)。这种思想很常用。

代码技巧:

①本题有一个坑,就是同一个关系(Ai,Bi)可能被输入多次,可重复的输入对于本题来说,是没有意义的,所有要对每一个关系判重。由于这是一组关系,是二元的,无法简单的通过vis[]数组实现,所以可以通过map<pair<int,int> bool> exist;实现。

if(exist[make_pair(a,b)])
    continue;
exist[make_pair<a,b>] = true;        //标志<a,b>已经出现过

代码:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define Case(T)         int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b)              for(int i = a; i < b; ++i)
#define fd(i,a,b)              for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val)    fill(a,a+n,val)
#define Scand(n)       scanf("%d",&n)
#define Scans(s)       scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

int n,I,h,r;
int help[maxn], height[maxn];
map<pair<int, int>, bool> exist;

int main()
{
#ifndef ONLINE_JUDGE
    //Fin;
#endif // ONLINE_JUDGE
    while(scanf("%d%d%d%d",&n,&I,&h,&r) == 4){
        fi(help, maxn-5, 0);    fi(height, maxn-5, 0);
        for(int i = 0; i < r; ++i){
            int a,b;
            scanf("%d%d",&a,&b);
            if(a > b)   swap(a, b);
            if(exist[make_pair(a, b)])
                continue;
            help[a+1]--; help[b]++;
            exist[make_pair(a, b)] = true;
        }
        for(int i = 1; i <= n; ++i){
            height[i] = height[i-1]+help[i];
        }
        int changee = h-height[I];
        for(int i = 1; i <= n; ++i){
            printf("%d",height[i]+changee);
            if(i != n)
                printf("\n");
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值