1. 程式人生 > >[POI2011]Meteors

[POI2011]Meteors

嘟嘟嘟


做了幾道題之後,對整體二分有點感覺了。


整體二分的本質就是二分答案。所以這道題二分的就是次數。
然後就是套路了,把小於\(mid\)的操作都新增減去,然後查詢,如果查詢的值\(x\)比給定值大,就把這個詢問放到左區間,否則減去\(x\),放到右區間。
具體的操作,要支援區間加和單點查,第一反應是線段樹,結果有兩個點TLE的很慘。所以改成了樹狀陣列差分維護字首和,竟然過了,而且還跑的特別塊。常數真是致命啊……

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 3e5 + 5;
inline ll read()
{
  ll ans = 0;
  char ch = getchar(), last = ' ';
  while(!isdigit(ch)) last = ch, ch = getchar();
  while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
  if(last == '-') ans = -ans;
  return ans;
}
inline void write(ll x)
{
  if(x < 0) x = -x, putchar('-');
  if(x >= 10) write(x / 10);
  putchar(x % 10 + '0');
}

int n, m, k, val[maxn];
vector<int> con[maxn];
struct Node
{
  int L, R, w, id;
}t[maxn << 1], tl[maxn << 1], tr[maxn << 1];
int ans[maxn];

ll c[maxn];
int lowbit(int x) {return x & -x;}
inline void clear(int pos)
{
  for(; pos <= m; pos += lowbit(pos))
    if(c[pos]) c[pos] = 0;
    else break;
}
inline void add(int pos, int d)
{
  if(!pos) return;
  for(; pos <= m; pos += lowbit(pos)) c[pos] += d;
}
inline ll query(int pos)
{
  ll ret = 0;
  for(; pos; pos -= lowbit(pos)) ret += c[pos];
  return ret;
}

inline void Change(Node q)
{
  if(q.L > q.R) add(q.L, q.w), add(1, q.w), add(q.R + 1, -q.w);
  else add(q.L, q.w), add(q.R + 1, -q.w);
}
inline void Clear(Node q)
{
  if(q.L > q.R) clear(q.L), clear(1), clear(q.R + 1);
  else clear(q.L), clear(q.R + 1);
}

inline void solve(int kl, int kr, int ql, int qr)
{
  if(ql > qr) return;
  if(kl == kr)
    {
      for(int i = ql; i <= qr; ++i)
    if(t[i].id > k + 1) ans[t[i].id - k - 1] = kl;
      return;
    }
  int mid = (kl + kr) >> 1, id1 = 0, id2 = 0;
  for(int i = ql; i <= qr; ++i)
    {
      if(t[i].id <= k + 1)
    {
      if(t[i].id <= mid) Change(t[i]), tl[++id1] = t[i];
      else tr[++id2] = t[i];
    }
      else
    {
      ll tot = 0; int x = t[i].id - k - 1;
      for(int j = 0; j < (int)con[x].size(); ++j)
        if((tot += query(con[x][j])) >= t[i].w) break;
      if(tot >= t[i].w) tl[++id1] = t[i];
      else t[i].w -= tot, tr[++id2] = t[i];
    }
    }
  for(int i = 1; i <= id1; ++i) if(tl[i].id <= k + 1 && tl[i].id <= mid) Clear(tl[i]);
  for(int i = 1; i <= id1; ++i) t[ql + i - 1] = tl[i];
  for(int i = 1; i <= id2; ++i) t[ql + id1 + i - 1] = tr[i];
  solve(kl, mid, ql, ql + id1 - 1);
  solve(mid + 1, kr, ql + id1, qr);
}

int main()
{
  n = read(); m = read();
  for(int i = 1, x; i <= m; ++i) x = read(), con[x].push_back(i);
  for(int i = 1; i <= n; ++i) val[i] = read();
  k = read();
  for(int i = 1; i <= k; ++i)
      t[i].L = read(), t[i].R = read(), t[i].w = read(), t[i].id = i;
  t[k + 1] = (Node){1, m, INF, k + 1};
  for(int i = 1; i <= n; ++i) t[k + 1 + i] = (Node){0, 0, val[i], k + 1 + i};
  solve(1, k + 1, 1, k + n + 1);
  for(int i = 1; i <= n; ++i)
    if(ans[i] > k) puts("NIE");
    else write(ans[i]), enter;
  return 0;
}