题目
有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);
}
}