整体二分
整体二分
我们发现,题目满足二分性质, 但对于每一个询问二分又十分的慢,我们可以离线, 把答案一样的询问放在一起处理
- 引入一道题
P3527 [POI2011]MET-Meteors
Solution
我们需要区间加和单点查询, 考虑使用树状数组
定义一个函数 $ f(l, r, L, R) $ 代表当前二分区间是 $ [l, r] $ , 答案在这个区间里的询问从 \(L\) 排到 \(R\)
设 $ mid = (l + r) >> 1 $ 我们把 $ [l, mid] $ 这段操作加进去
根据这次的操作,把询问分成两部分, 答案在 $ [l, mid] $ 内的和在 $ [mid + 1, r]$ 内的,递归直到 \(l = r\)
时间复杂度???
对于这道提来说, 类似线段树一样递归有 $ log m$ 层, 每层有 $ m $ 个操作,和 $ q $ 次询问
总体复杂度为 $ O((m + n) long^2 m) $
\(code\)
#include<iostream>
#include<cstdio>
#include<vector>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define rg register
char ss[1 << 17], *A = ss, *B = ss;
inline char gc(){ if(A == B) { B = (A = ss) + fread(ss, 1, 1 << 17, stdin); if(A ==B) return EOF; } return *A++; }
inline int read(){
rg char ch = gc();
rg int x = 0, f = 0;
while(! isdigit(ch)) f |= (ch == '-'), ch = gc();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
return f ? -x : x;
}
const int N = 3e5 + 7;
long long g[N << 1];
int n, m, k;
inline void modify(int x, int d){
for(int i = x; i; i ^= (i & -i)) g[i] += d;
}
inline long long ask(int x){
long long res = 0;
for(int i = x; i <= (m << 1); i += (i & -i)) res += g[i];
return res;
}
inline void add(int l, int r, int d){
modify(r, d);
modify(l - 1, -d);
}
int o[N], p[N], id[N], ans[N];
int pre[N], pre_id[N];
vector<int> have[N];
struct node{
int l, r, d;
inline void init() { l = read(), r = read(), d = read(); }
inline void modify() { :: add(l, r, d); }
inline void in_modify() { :: add(l, r, -d); }
}q[N];
#define ll long long
void solve(int l, int r, int L, int R){
if(L > R) return;
if(l == r) {
for(int i = L; i <= R; ++i) ans[id[i]] = l;
return;
}
int mid = (l + r) >> 1;
int tl = L - 1, tr = R + 1;
for(int i = l; i <= mid; ++i) q[i].modify();
for(int i = L; i <= R; ++i){
ll tmp = 0;
for(auto &x : have[id[i]]){
tmp += ask(x) + ask(x + m);
if(tmp >= p[i]) break;
}
if(tmp >= p[i]) pre[++tl] = p[i], pre_id[tl] = id[i];
else pre[--tr] = p[i] - tmp, pre_id[tr] = id[i];
}
for(int i = l; i <= mid; ++i) q[i].in_modify();
memcpy(p + L, pre + L, 4 * (tl - L + 1));
memcpy(id + L, pre_id + L, 4 * (tl - L + 1));
memcpy(p + tl + 1, pre + tl + 1, 4 * (R - tl));
memcpy(id + tl + 1, pre_id + tl + 1, 4 * (R - tl));
//for(int i = L; i <= tl; ++i) p[i] = pre[i], id[i] = pre_id[i];
//for(int i = R; i >= tr; --i) p[i] = pre[i], id[i] = pre_id[i];
solve(l, mid, L, tl); solve(mid + 1, r, tr, R);
}
signed main(){
n = read(), m = read();
for(int i = 1; i <= m; ++i) have[read()].push_back(i);
for(int i = 1; i <= n; ++i) p[i] = read(), id[i] = i;
k = read();
for(int i = 1; i <= k; ++i) q[i].init();
for(int i = 1; i <= k; ++i) if(q[i].r < q[i].l) q[i].r += m;
q[k + 1].l = 1, q[k + 1].r = 1, q[k + 1].d = 0;
solve(1, k + 1, 1, n);
for(int i = 1; i <= n; ++i) (ans[i] == k + 1) ? puts("NIE") : printf("%d\n", ans[i]);
return 0;
}