1. 程式人生 > >Codeforces 1070C Cloud Computing 二分 + 樹狀陣列 + 掃描線

Codeforces 1070C Cloud Computing 二分 + 樹狀陣列 + 掃描線

                                                          Codeforces 1070C  Cloud Computing

將左右端點分配到1-n上的各個點,然後從1-n 進行掃描線處理,維護兩個數狀陣列,c[i],b[i],  c[i]維護當前時間下,可用方案按時間排序的數量,b[i] 維護 i*c[i] 即價格和, 然後二分適合的價格,滿足 數量 >= k, 如果 > k 回退一部分,注意longlong,wrong 樣例 32,33 都是爆int的原因!

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6+10;
typedef long long LL;

LL b[maxn];
LL c[maxn];
LL cc[maxn];
LL p[maxn];
LL n,k,m,li,ri,ci,pi;
vector <int> l[maxn];
vector <int> r[maxn];
int N = 1e6+2;
bool check(int mid)
{
    LL res = 0;
    for(int x = mid; x; x -= x&-x) res += c[x];
    if(res >= k) return true;
    else return false;
}

int main()
{

  scanf("%lld%lld%lld",&n,&k,&m);
  for(int i = 1; i <= m; i++)
  {
      scanf("%lld%lld%lld%lld",&li,&ri,&cc[i],&p[i]);
      l[li].push_back(i);
      r[ri].push_back(i);
  }
  memset(c,0,sizeof(c));
  memset(b,0,sizeof(b));
  LL ans = 0;
  for(int i = 1; i <= n; i++)
  {
    for(int j = 0; j < l[i].size(); j++)
       {
        int t = l[i][j];
      //  cout <<t <<endl;
        for(int x = p[t]; x < N; x += x&-x) c[x] += cc[t];
        for(int x = p[t]; x < N; x += x&-x) b[x] += p[t]*cc[t];
       }

    int st = 0, ed = 1e6+1;
    while(ed - st > 1)
    {
        int mid = st + (ed-st)/2;
        if(check(mid)) ed = mid;
        else st = mid;
    }

    LL num = 0,res = 0;
    for(int x = ed; x ; x-= x&-x)  num += c[x],res += b[x];

    LL num1 = 0;
    for(int x = st; x; x -= x&-x)  num1 += c[x];
    if(num1 == num)  ed = st;
    ans += res - max(0LL,(num-k))*ed;
    //cout <<ed << " " << res << " " << num << endl;
    for(int j = 0; j < r[i].size(); j++)
      {
       int t = r[i][j];
       for(int x = p[t]; x < N; x += x&-x) c[x] -= cc[t];
       for(int x = p[t]; x < N; x += x&-x) b[x] -= p[t]*cc[t];
      }
  }
  printf("%lld\n",ans);
  return 0;
}