[BZOJ2527][POI2011]Meteors(整體二分+樹狀陣列)
阿新 • • 發佈:2018-11-10
Address
Solution
容易想到對於每個詢問二分答案,但一次判定是
的。
整體二分的思想就是把所有的詢問放在一起二分。
設
表示答案範圍為
,處理第
個詢問到第
個詢問。
(1)取
。
(2)用一個樹狀陣列維護每一個位置下了多少場隕石雨。將第
場隕石雨到第
場隕石雨全部加入樹狀陣列。
(3)按順序考慮每個詢問,把詢問分成兩類:
①在
內可以收集夠隕石。
②在
內沒收集到足夠的隕石。
把詢問分成兩組,
為①類,
為②類。
如果一個②類詢問是國家
,且樹狀陣列上查到在
內國家
收集到的隕石數為
,則把
減掉
。
(4)遞迴到
和
。
時間複雜度
。
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Bitr(x, n) for (; x <= n; x += x & -x)
#define Bitl(x) for (; x; x -= x & -x)
using namespace std;
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 3e5 + 5;
int n, m, o[N], p[N], K, l[N], r[N], a[N], q[N], q1[N], q2[N], ans[N];
ll A[N];
vector<int> num[N];
void clean(int x)
{
Bitr(x, m) A[x] = 0;
}
void change(int x, int v)
{
Bitr(x, m) A[x] += v;
}
ll ask(int x)
{
ll res = 0;
Bitl(x) res += A[x];
return res;
}
void interv(int l, int r, int v)
{
change(l, v); change(r + 1, -v);
}
void cirv(int l, int r, int v)
{
if (l <= r) interv(l, r, v);
else interv(l, m, v), interv(1, r, v);
}
void cleanv(int l, int r)
{
clean(l); clean(r + 1);
}
void cleancir(int l, int r)
{
if (l <= r) cleanv(l, r);
else cleanv(l, m), cleanv(1, r);
}
void jiejuediao(int lval, int rval, int lq, int rq)
{
if (lval > rval || lq > rq) return;
int i, j, mid = lval + rval >> 1, tot1 = 0, tot2 = 0, tot = lq - 1;
For (i, lval, mid) cirv(l[i], r[i], a[i]);
For (i, lq, rq)
{
int j, z = num[q[i]].size(); ll tmp = 0;
For (j, 0, z - 1)
{
tmp += ask(num[q[i]][j]);
if (p[q[i]] <= tmp) break;
}
if (p[q[i]] <= tmp) ans[q[i]] = mid, q1[++tot1] = q[i];
else p[q[i]] -= tmp, q2[++tot2] = q[i];
}
For (i, 1, tot1) q[++tot] =