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
",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;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11205563.html