ACWing 268 流星

Problem


Solution

Thinking 1

修改操作显然是区间加,可以整体二分。
但是如果这个区间按照国家来看的话,就不是连续的了,然道要\(n\log{n}\)单点修改?不必,反过来,把每个国家的基站存起来,询问时直接每个基站的贡献相加。

Thinking 2

每个基站的贡献可以用单点查询得到,BIT维护。

Thinking 3

然后变成了整体二分板子。

# include <bits/stdc++.h>
using namespace std;
# define int long long 
const int N = 3e5 + 5;
int n,m,k;
vector <int> g[N];
int p[N];
int a[N],ans[N];
int lc[N],rc[N];
template <typename T> void read(T &x) {int w = 1;x = 0; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') w = -1; ch = getchar();} while(isdigit(ch)){x = x * 10 + ch - '0'; ch = getchar();} x *= w;}

struct node
{
    int l,r,a;
    node() {}
    node(int _l,int _r,int _a) : l(_l),r(_r),a(_a) {}
}A[N];
struct BIT
{
    int T[N];
    int lowbit(int x) {return x & (-x);}
    void add(int x,int d)
    {
        while(x <= m)
        {
            T[x] += d,x += lowbit(x);
        }
        return;
    }
    int query(int x)
    {
        int total = 0;
        while(x)
        {
            total += T[x];x -= lowbit(x);
        }
        return total;
    }
    void update(int l,int r,int d)
    {
        add(l,d),add(r + 1,-d);
        return;
    }
}T;
void dfs(int L,int R,int l,int r)
{
    if(l > r) return;
    // printf("L = %lld,R = %lld,l = %lld,r = %lld\n",L,R,l,r);
    if(L == R)
    {
        for(int i = l; i <= r; i++) ans[a[i]] = L;
        return;
    }
    int mid = (L + R) >> 1,lt = 0,rt = 0;
    for(int i = L; i <= mid; i++)
    {   
        if(A[i].l <= A[i].r) T.add(A[i].l,A[i].a),T.add(A[i].r + 1,-A[i].a);
        else T.add(A[i].l,A[i].a),T.add(1,A[i].a),T.add(A[i].r + 1,-A[i].a);
        // if(A[i].l <= A[i].r) T.update(A[i].l,A[i].r,A[i].a);
        // else T.update(A[i].l,m,A[i].a),T.update(1,A[i].r,A[i].a);
    }
    for(int i = l; i <= r; i++)
    {
        int cur = 0;
        for(int j = 0; j < (int)g[a[i]].size(); j++)
        {
            cur += T.query(g[a[i]][j]);
            if(cur >= p[a[i]]) break;
        }
        if(cur >= p[a[i]]) lc[++lt] = a[i];
        else rc[++rt] = a[i],p[a[i]] -= cur;
    }
    for(int i = L; i <= mid; i++)
    {
        if(A[i].l <= A[i].r) T.add(A[i].l,-A[i].a),T.add(A[i].r + 1,A[i].a);
        else T.add(A[i].l,-A[i].a),T.add(1,-A[i].a),T.add(A[i].r + 1,A[i].a);
        // if(A[i].l <= A[i].r) T.update(A[i].l,A[i].r,-A[i].a);
        // else T.update(A[i].l,m + 1,A[i].a),T.update(1,A[i].r,-A[i].a);
    }
    for(int i = 1; i <= lt; i++) a[l + i - 1] = lc[i];
    for(int i = 1; i <= rt; i++) a[l + lt + i - 1] = rc[i];
    dfs(L,mid,l,l + lt - 1);
    dfs(mid + 1,R,l + lt,r);
    return; 
}
signed main(void)
{
    read(n),read(m);
    for(int i = 1; i <= m; i++)
    {
        int x;
        read(x);
        g[x].push_back(i);
    }
    for(int i = 1; i <= n; i++)
    {
        read(p[i]);
        a[i] = i;
    }
    read(k);
    for(int i = 1; i <= k; i++)
    {
        int l,r,a;
        read(l),read(r),read(a);
        A[i] = node(l,r,a);
    }
    A[k + 1] = node(1,m,1e9 + 7);
    dfs(1,k + 1,1,n);
    for(int i = 1; i <= n; i++)
    {
        if(ans[i] > k) printf("NIE\n");
        else printf("%lld\n",ans[i]);
    }
    return 0;
}
posted @ 2021-05-29 20:17  luyiming123  阅读(42)  评论(0编辑  收藏  举报