BZOJ5321 JXOI2017加法(二分答案+贪心+堆+树状数组)

  二分答案后得到每个位置需要被加的次数。考虑贪心。从左到右考虑每个位置,将以该位置为左端点的区间按右端点从大到小加进堆。看该位置还需要被加多少次,如果不需要加了就不管,否则取堆顶区间将其选择,BIT实现区间覆盖。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int T,n,m,k,a[N],c[N],tree[N];
priority_queue<int> q;
vector<int> b[N];
void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;}
int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
bool check()
{
    for (int i=1;i<=n;i++) tree[i]=0;int cnt=0;
    while (!q.empty()) q.pop();
    for (int i=1;i<=n;i++) add(i,c[i]-c[i-1]);
    for (int i=1;i<=n;i++)
    {
        for (int j=0;j<b[i].size();j++) q.push(b[i][j]);
        int x=query(i);
        for (;x>0;x--)
        {
            if (q.empty()) return 0;
            int y=q.top();q.pop();
            if (y<i) return 0;
            add(i,-1),add(y+1,1);
            if ((++cnt)>k) return 0;
        }
    }
    return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj5321.in","r",stdin);
    freopen("bzoj5321.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read();
    while (T--)
    {
        n=read(),m=read(),k=read();int p=read();
        int l=100000000,r,ans;
        for (int i=1;i<=n;i++) l=min(l,a[i]=read()),b[i].clear();
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            b[x].push_back(y);
        }
        r=l+m*p;
        while (l<=r)
        {
            int mid=l+r>>1;
            for (int i=1;i<=n;i++) c[i]=mid<=a[i]?0:(mid-a[i]-1)/p+1;
            if (check()) l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10076028.html