Tallest Cow

Tallest Cow

有一个长度为n的正整数序列\(\{a_i\}\),现在给出其中最大的数字为h,并给出R组关系,第i组关系用二元组\((l_i,r_i)\)表示,表示\(a_{l_i+1}\sim {r_i-1}\)间的数字都要比\(a_{l_i},a_{r_i}\)小,询问对于每个i,\(a_i\)的最大值。

不妨设一个序列\(\{b_i\}\),初始全部为0,对于每一组关系,如\((l_i,r_i)\),那么就把\(b_{l_i+1}\sim b_{r_i-1}\)全部减1,显然这样是\(O(n^2)\),考虑优化,容易知道这是区间的维护,除了考虑写难写的线段树和分块外,区间问题还有一个著名的思想,就是将区间的信息保存在两个端点上,通过前缀和体现信息,不妨设一个序列\(\{c_i\}\),初始化为0,对于关系\((l_i,r_i)\)而言,就\(--c_{l_i+1},++c_{r_i}\),这样维护出来的序列c的前缀和\(\{s_i\}\),易知\(s_i=b_i\),于是问题得到解决。

最后因为关系会重复输入,于是我们还要hash判重,但是我们还是可以最后做到\(O(n)\)

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define key 156511
#define swap(x,y) x^=y^=x^=y
using namespace std;
struct data{
    data*next;int j,k;
}*head[key],*pt;
int A[10001];
il bool exist(int,int);
il void insert(int,int);
int main(){
    int n,s,h,r;
    scanf("%d%d%d%d",&n,&s,&h,&r);
    for(int i(1),j,k;i<=r;++i){
        scanf("%d%d",&j,&k);if(j>k)swap(j,k);
        if(exist(j,k))--A[j+1],++A[k],insert(j,k);
    }
    for(int i(1);i<=n;++i)A[i]+=A[i-1],printf("%d\n",A[i]+h);
    return 0;
}
il bool exist(int j,int k){
    int H((j+k*10001)%key);
    for(pt=head[H];pt!=NULL;pt=pt->next)
        if(pt->j==j&&pt->k==k)return false;
    return true;
}
il void insert(int j,int k){
    int H((j+k*10001)%key);
    pt=new data,pt->j=j,pt->k=k,
        pt->next=head[H],head[H]=pt;
}

posted @ 2019-07-18 10:24  a1b3c7d9  阅读(290)  评论(0编辑  收藏  举报