LG 题解 SP10264 METEORS - Meteors

题目传送

双倍经验

更好的阅读体验?

前置芝士

  • 整体二分
  • 树状数组

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\n", ans[i]) : puts("NIE");
    return 0;
}

posted @ 2021-09-03 18:12  Suzt_ilymtics  阅读(62)  评论(0编辑  收藏  举报