前置芝士
- 整体二分
- 树状数组
Solution
一道经典的整体二分题目。
一个显然的想法是二分操作次数。
假设二分到了 ([l,r]) 这段操作区间,下一个分解点为 (mid)。
发现陨石雨的实质是区间加,那么我们可以在树状数组上差分。
先执行所有陨石雨操作,直接把在 ([l,mid]) 区间的所有陨石雨的贡献统计。
然后遍历答案在 ([l,r]) 区间的每个国家,暴力统计每个国家能收集到的陨石即可,树状数组单点查询操作。(当然你需要用 vector
预处理每个国家能收集那几个地方的陨石)
如果能够满足,就把它放进 ([l,mid]) 对应的序列中,否则减去这一次的贡献,把它放进 ([mid+1,r]) 对应的序列中。
不断递归下去即可。
直到 (l=r) 就可以确定答案了。
对于判断无解的时候,我们可以直接从 ([1,Q+1]) 开始二分((Q) 表示有 (Q) 次陨石雨),那么最后答案为 (Q+1) 的国家即为找不到答案的国家。
因为轨道是个环形,所以一个小 Trick 是把 (l>r) 的操作拆成两部分。但在双倍经验那道题上有点卡空间,只在需要的地方开 unsigned long long
就行。
你问我为什么要开 unsigned long long
?因为极限数据下会爆 long long
。
剩下的细节看代码吧。
Code
/*
Work by: Suzt_ilymics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL unsigned long long
#define orz cout<<"lkp AK IOI!"<<endl
using namespace std;
const int MAXN = 3e5+50;
const int INF = 1e9+7;
const int mod = 1e9+7;
struct node {
int l, r, c, id, type;
}q[MAXN*3], q1[MAXN*3], q2[MAXN*3];
int n, m, Q, tot = 0;
int p[MAXN], ans[MAXN];
vector<int> fr[MAXN];
int read(){
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
return f ? -s : s;
}
namespace BIT {
LL sum[MAXN];
int lb(int x) { return x&-x; }
void Modify(int pos, int val) { for( ; pos <= m; pos += lb(pos)) sum[pos] += val; }
LL Query(int pos) { LL res = 0; for( ; pos; pos -= lb(pos)) res += sum[pos]; return res; }
}
void Solve(int l, int r, int ql, int qr) {
if(ql > qr) return ;
if(l == r) {
for(int i = ql; i <= qr; ++i) if(q[i].type) ans[q[i].id] = l;
return ;
}
int mid = (l + r) >> 1, cnt1 = 0, cnt2 = 0;
for(int i = ql; i <= qr; ++i) {
if(!q[i].type) {
if(q[i].id <= mid) {
BIT::Modify(q[i].l, q[i].c);
BIT::Modify(q[i].r+1, -q[i].c);
q1[++cnt1] = q[i];
} else {
q2[++cnt2] = q[i];
}
} else {
LL sum = 0;
for(int j = 0, M = fr[q[i].id].size(); j < M; ++j) sum += BIT::Query(fr[q[i].id][j]);
if(sum >= q[i].c) {
q1[++cnt1] = q[i];
} else {
q[i].c -= sum;
q2[++cnt2] = q[i];
}
}
}
for(int i = 1; i <= cnt1; ++i) if(!q1[i].type) BIT::Modify(q1[i].l, -q1[i].c), BIT::Modify(q1[i].r+1, q1[i].c);
for(int i = 1; i <= cnt1; ++i) q[ql + i - 1] = q1[i];
for(int i = 1; i <= cnt2; ++i) q[ql + cnt1 + i - 1] = q2[i];
Solve(l, mid, ql, ql + cnt1 - 1);
Solve(mid + 1, r, ql + cnt1, ql + cnt1 + cnt2 - 1);
}
signed main()
{
n = read(), m = read();
for(int i = 1; i <= m; ++i) fr[read()].push_back(i);
for(int i = 1; i <= n; ++i) p[i] = read();
Q = read();
for(int i = 1, l, r, v; i <= Q; ++i) {
l = read(), r = read(), v = read();
if(l <= r) q[++tot] = (node){l, r, v, i, 0};
else q[++tot] = (node){1, r, v, i, 0}, q[++tot] = (node){l, m, v, i, 0};
}
for(int i = 1; i <= n; ++i) q[++tot] = (node){0, 0, p[i], i, 1};
Solve(1, Q + 1, 1, tot);
for(int i = 1; i <= n; ++i) ans[i] <= Q ? printf("%d
", ans[i]) : puts("NIE");
return 0;
}