[POI2011]MET-Meteors

给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值
https://www.luogu.org/problemnew/show/P3527

每一次计算出mid时刻每个国家已经收集的数量,把所有能够完成国家的放在左边,所有不能完成的国家放在右边。左边继续二分mid以下的时间,右边继续二分mid以上的时间。
判断能否完成,用树状数组暴力更新即可。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
LL c[300005];
vector<int> G[300005];
int L[300005],R[300005],val[300005];
int P[300005],ans[300005];
int q[300005],q1[300005],q2[300005];
int n,m,k,now=0;
inline int read() {
    int sum=0;char ch=0;
    while (ch>'9' || ch<'0') ch=getchar();
    while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
    return sum;
}
inline int lowbit(int x) {
    return x&-x;
}
inline void add(int x,int v) {
    for (;x<=m;x+=lowbit(x)) c[x]+=v;
}
inline LL query(int x) {
    LL tmp=0;
    for (;x>0;x-=lowbit(x)) tmp+=c[x];
    return tmp;
}
inline void update(int l,int r,int v) {
    if (l<=r) {
        add(l,v);add(r+1,-v);
    }
    else {
        add(1,v);add(r+1,-v);
        add(l,v);add(m+1,-v);
    }
}
void bs(int l,int r,int s,int t) {//lr二分k st代表国家位置 
    if (s>t) return;
    if (l==r) {
        for (int i=s;i<=t;i++) ans[q[i]]=l;
        return;
    }
    int mid=(l+r)>>1;
    while (now<mid) now++,update(L[now],R[now],val[now]);
    while (now>mid) update(L[now],R[now],-val[now]),now--;
    int s1=0,s2=0;
    for (int i=s;i<=t;i++) {
        LL tmp=0;
        int x=q[i];
        for (int j=0;j<G[x].size();j++) {
            tmp+=query(G[x][j]);
            if (tmp>=P[x]) break;
        }
        if (tmp>=P[x]) q1[++s1]=x;
        else q2[++s2]=x;
    }
    for (int i=1;i<=s1;i++) q[s+i-1]=q1[i];
    for (int i=1;i<=s2;i++) q[s+s1+i-1]=q2[i];
    bs(l,mid,s,s+s1-1);
    bs(mid+1,r,s+s1,t);
}
int main() {
    n=read();m=read();
    for (int i=1;i<=m;i++) G[read()].push_back(i);
    for (int i=1;i<=n;i++) {
        P[i]=read();
        q[i]=i;
    }
    k=read();
    for (int i=1;i<=k;i++) {
        L[i]=read();R[i]=read();val[i]=read();
    }
    bs(1,k+1,1,n);
    for (int i=1;i<=n;i++) {
        if (ans[i]==k+1) printf("NIE\n");
        else printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014304190/article/details/80038514