BZOJ4293 [PA2015]Siano(线段树)

传送门
这Seg确实不好写,不过因为它与ai的相对顺序无关,所以,我们在对ai排序之后,就可做了。维护一个区间最大值,维护一个和,维护一个区间赋值的懒标记,再维护一个时间变化的标记就可以了。
因为不论怎样在排序过后的序列里面右边的一定不小于左边的,所以我们可以在线段树里面二分来找到每一次操作的开始位置,然后就可以区间修改了。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 500005
#define LL long long
LL a[MAXN], pre, tm, b, lst, n, m, sm[MAXN];
struct node {
    LL sum, lazy, v, dt; //dt -> delta_time
    node(){lazy = -1;}
} t[MAXN<<1];
#define idx(l, r) (l+r)|(l!=r)
inline void GET(LL &n) {
    char c; n = 0;
    do c = getchar(); while('0' > c || c > '9');
    do n = n*10+c-'0', c=getchar(); while('0' <= c && c <= '9');
}
inline void fz(int l, int r, LL dt) {
    t[idx(l, r)].v += dt*a[r]; t[idx(l, r)].sum += (sm[r]-sm[l-1]) * dt; t[idx(l, r)].dt += dt;
}
inline void pd(int l, int r) {
    int mid = (l + r) >> 1, i = idx(l, r);
    if(~t[i].lazy) {
        t[idx((mid+1), r)].lazy = t[idx(l,mid)].lazy = t[i].lazy;
        t[idx((mid+1), r)].dt = t[idx(l,mid)].dt = 0;
        t[idx((mid+1), r)].v = t[idx(l,mid)].v = t[i].lazy;
        t[idx((mid+1), r)].sum = (r-mid)*t[i].lazy; t[idx(l,mid)].sum = (mid-l+1)*t[i].lazy;
        t[i].lazy = -1;
    }
    if(t[i].dt) {
        fz(l, mid, t[i].dt); fz(mid+1, r, t[i].dt); t[i].dt = 0;
    }
}
inline void pu(int l, int r) {
    int mid = (l + r) >> 1;
    t[idx(l, r)].sum = t[idx(l, mid)].sum + t[idx((mid+1), r)].sum;
    t[idx(l, r)].v = t[idx((mid+1), r)].v;
}
int Find(int l, int r) {
    if(l == r) return l;
    int mid = (l + r) >> 1;
    pd(l, r);
    if(t[idx(l, mid)].v >= b) return Find(l, mid);
    return Find(mid+1, r);
}
int L;
LL Modify(int l, int r) {
    if(r < L) return 0;
    int mid = (l + r) >> 1; LL ans;
    if(L <= l) { ans = t[idx(l, r)].sum; t[idx(l, r)].dt = 0; t[idx(l, r)].sum = (r-l+1)*b; t[idx(l, r)].v = b; t[idx(l, r)].lazy = b; return ans; }
    pd(l, r); ans = Modify(l, mid) + Modify(mid+1, r);
    pu(l, r); return ans;
}
int main() {
    GET(n); GET(m);
    for(int i = 1; i <= n; ++ i) GET(a[i]);
    sort(a+1, a+n+1); for(int i = 1; i <= n; ++ i) sm[i] = sm[i-1] + a[i];
    for(int i = 1; i <= m; ++ i) {
        GET(tm); GET(b); fz(1, n, tm-lst); lst = tm;
        if (t[idx(1, n)].v < b){ puts("0"); continue; }
        L = Find(1, n); printf("%lld\n", Modify(1, n)-b*(n-L+1));
    }
    return 0;
}

你可能感兴趣的:(BZOJ4293 [PA2015]Siano(线段树))