codeforces 589G(birnary serach + bit + 离线)

题意:

很明显给定n,m(n,m<=2e5)

并给定一个长度为m的数组 , 代表m天每个人可以工作多长时间。

下面共有n对二元组,(d,t)代表第i个人需要完成工作量为t的任务,可是每天要么不干,要么先拿出d的时间来准备,然后剩下的可行时间工作,问每个人最少需要到第几天完成任务。

分析:
这样的题目,很明显的思路,离线排序使之产生顺序化,然后从一边开始考虑,是的前面兼顾后面的条件,加上点数据结构即可AC。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
typedef long long ll;
using namespace std;
#define lowbit(x) (x&(-x))
const int N = 2e5 + 1000;
#define int long long
typedef pair<int,int> pii;
#define val first
#define id second
pii a[N];
pair<pii,int> b[N];
int n,ans[N],m;
struct bit_
{
    int C[N];
    void init()
    {
        memset(C,0,sizeof(C));
    }
    int sum(int x)
    {
        int ret = 0;
        while(x >0)
        {
            ret += C[x];
            x-=lowbit(x);
        }
        return ret;
    }
    void add(int x,int d)
    {
        while(x <= m)
        {
            C[x] +=d;
            x+=lowbit(x);
        }
    }
} c , cnt;
main()
{
   cin>>n>>m;
    rep1(i,1,m)
    {
        int d;
       cin>>d;
        a[i]=pii(d,i);
    }
    rep1(i,1,n)
    {
        int x, y;
       cin>>x>>y;
        b[i] = make_pair(pii(x,y),i);
    }
    sort(a+1,a+1+m);
    sort(b+1,b+1+n);
    c.init(); cnt.init();
    int posi = m;
    for(int i=n; i>=1; i--)
    {
        pii te = b[i].first;
        int lim = te.first;
        while(posi && a[posi].val>lim)
        {
            c.add(a[posi].id,a[posi].val);
            cnt.add(a[posi].id,1);
            posi--;
        }
        if(c.sum(m) - (m-posi)*lim < te.second)
        {
            ans[b[i].second ] = 0;
            continue;
        }
        else
        {
            int x = 0, y=m;
            while(x < y)
            {
                int mid = (x+y)>>1;
                if(c.sum(mid) - (cnt.sum(mid)*lim)<te.second ) x = mid+1;
                else y=mid;
            }
           ans[b[i].second ] = x;
        }
    }
    rep1(i,1,n) {
        if(i>1) printf(" ");
        printf("%d",(int)ans[i]);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值