poj3263Tallest Cow 前缀和

题目

有N头牛站成一行。两头牛能够相互看见,当且仅当它们中间的牛身高都比它们矮。现在,我们只知道其中最高的牛是第p头,它的身高是H,不知道剩余N-1头牛的身高。但是,我们还知道M对关系,每对关系都指明了某两头牛Ai和Bi可以相互看见。求每头牛的身高最大可能是多少。1<=N,M<=10000,1<=H<=1000000

题解

因为给出的是牛与牛之间身高的关系,可以先将每头牛的高度视为0,然后对于一对可以互相看见的牛,将它们之间的牛身高全部-1,这样操作之后,最高的牛身高为0,得出的其它牛身高相当于和最高的牛身高的差距,所以其它牛的实际身高为算出的身高+最高牛身高H

但是,如果对于每个区间都枚举一遍处理,时间复杂度会比较不友好O(nm),所以要有更好的算法。
当然,区间处理这种东西线段树可以轻松胜任,所以用线段树也可以
这里有一个更好的算法(当然不是我自己想的)
设一个新的数组f,对于一对关系Ai,Bi,将f[a+1]–,f[b]++。而牛i的身高即为f[1]+f[2]+…+f[i]+H。因为a之前的数这样可以不受a的影响,a之后b之前的数受f[a+1]–的影响,b之后的数因为f[b]++而可以不受f[a+1]–的影响。这样一来,区间操作就转化为了对单点的操作,可以线性得出答案
这种思想很有用,码量少,实用性好

代码

#include <cstdio>
#include <algorithm>

using namespace std;

int n,i,h,r;
int f[10004];
int c[10004][10004];

int main(){
    scanf("%d%d%d%d",&n,&i,&h,&r);
    for (;r;r--){
        int a,b;
        scanf("%d%d",&a,&b);
        if (a>b) swap(a,b);
        if (c[a][b]) continue;
        f[a+1]--;f[b]++;c[a][b]=1;
    }
    for (int i=1;i<=n;i++){
        f[i]+=f[i-1];
        printf("%d\n",f[i]+h);
    }
}

猜你喜欢

转载自blog.csdn.net/yjy_aii/article/details/81636032