[BOI2011]MET-Meteors

题目:洛谷P3527。

题目大意:
n个国家在某星球上建立了m个空间站(一个空间站只属于一个国家),空间站围成一个环。
现在知道要下k天陨石,每天都在一个区间内下,每个点都下同样多的(若r>l,则说明区间是\(1~r和l~m\))。
每个国家有一个目标陨石数。
问每个国家最早在什么时候达到目标陨石数。若下完了还达不到,则输出NIE。
解题思路:
整体二分。
对所有的国家一起二分,用树状数组维护前缀(后缀)。
对于每个答案,将能达到目标的国家和达不到的国家分开,然后继续二分即可。
时间复杂度\(O(n\log^2 n)\)。

线段树被卡常┭┮﹏┭┮

C++ Code:

#include<cstdio>
#include<vector>
#include<cctype>
#define LoveLive long long
const int M=500005,N=300005;
int k,n,m,P[N],q[N],ans[N],now,tmp[N];std::vector<int>a[N];
LoveLive Bit[M];
bool type[N];
inline int readint(){
    int c=getchar(),d=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
struct stars{
    int l,r,s;
}d[N];
inline void add(int i,int a){for(;i<=m;i+=i&-i)Bit[i]+=a;}
inline LoveLive query(int i){LoveLive a=0;for(;i;i-=i&-i)a+=Bit[i];return a;}
inline void update(int tm,int det){
    if(d[tm].l<=d[tm].r)add(d[tm].l,det*d[tm].s),add(d[tm].r+1,-det*d[tm].s);else
    add(1,det*d[tm].s),add(d[tm].r+1,-det*d[tm].s),add(d[tm].l,det*d[tm].s);
}
void solve(int l,int r,int l1,int l2){
    if(l1>l2)return;
    if(l==r){
        for(int i=l1;i<=l2;++i)ans[q[i]]=l;
        return;
    }
    int mid=l+r>>1;
    while(now<mid)update(++now,1);
    while(now>mid)update(now--,-1);
    int cnt=0;
    for(int i=l1;i<=l2;++i){
        LoveLive p=0;
        int&id=q[i];
        for(int j=0,dd=a[id].size();j<dd&&p<P[id];++j)p+=query(a[id][j]);
        if(p>=P[id])type[id]=1,++cnt;else
        type[id]=0;
    }
    int t1=l1,t2=l1+cnt;
    for(int i=l1;i<=l2;++i)
    if(type[q[i]])tmp[t1++]=q[i];else
    tmp[t2++]=q[i];
    for(int i=l1;i<=l2;++i)q[i]=tmp[i];
    solve(l,mid,l1,t1-1);
    solve(mid+1,r,t1,l2);
}
int main(){
    n=readint(),m=readint();
    for(int i=1;i<=m;++i)a[readint()].push_back(i);
    for(int i=1;i<=n;++i)P[q[i]=i]=readint();
    k=readint()+1;
    for(int i=1;i<k;++i){
        d[i].l=readint();
        d[i].r=readint();
        d[i].s=readint();
    }
    d[k]=(stars){1,m,1e9};
    solve(1,k,1,n);
    for(int i=1;i<=n;++i)
    if(ans[i]<k)printf("%d\n",ans[i]);else puts("NIE");
    return 0;
}

 

posted @ 2018-07-10 20:07  Mrsrz  阅读(190)  评论(0编辑  收藏  举报