[POI2011]MET-Meteors

Description:

给你一个环,每个点属于一个国家,每次进行区间加,问每个国家第几次加之后总和达到一个数

Hint:

\(n \le 3*10^5\)

Solution:

无语这题,要出整体二分就直接出,搞一个环来恶心人,还有那个国家,害我调好久

可以发现题中的第几次可以二分,预处理一下国家直接搞就行

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=1e6+5;
ll n,m,k,cnt,hd[mxn];

inline ll read() {
    char c=getchar(); ll x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(ll &x,ll y) {if(x<y) x=y;}
inline void chkmin(ll &x,ll y) {if(x>y) x=y;}

struct Q {
    ll id; ll p;
}q[mxn],tl[mxn],tr[mxn];
vector<ll > g[mxn];
ll ans[mxn],t[mxn],L[mxn],R[mxn],val[mxn];

ll lb(ll x) {return x&-x;}

void mod(ll x,ll y) {
    while(x<=2*m) t[x]+=y,x+=lb(x);
}

ll query(ll x) {
    ll res=0;
    while(x) res+=t[x],x-=lb(x);
    return res;
}

void solve(ll l,ll r,ll ql,ll qr) {
    if(ql>qr) return ;
    if(l==r) {
        for(ll i=ql;i<=qr;++i) ans[q[i].id]=l;
        return ;
    }
    ll mid=(l+r)>>1; ll lp=0,rp=0; //千万不能写外边
    for(ll i=l;i<=mid;++i) mod(L[i],val[i]),mod(R[i]+1,-val[i]);
    for(ll i=ql;i<=qr;++i) {
        ll res=0;
        for(ll j=0;j<g[q[i].id].size();++j) {
            res+=query(g[q[i].id][j]+m)+query(g[q[i].id][j]);
            if(res>q[i].p) break ;
        }
        if(res>=q[i].p) tl[++lp]=q[i];
        else tr[++rp]=q[i],tr[rp].p-=res; //这里要写进去
    }
    for(ll i=l;i<=mid;++i) mod(L[i],-val[i]),mod(R[i]+1,val[i]);
    for(ll i=ql;i<=ql+lp-1;++i) q[i]=tl[i-ql+1];
    for(ll i=ql+lp;i<=qr;++i) q[i]=tr[i-lp-ql+1];
    solve(l,mid,ql,ql+lp-1); solve(mid+1,r,ql+lp,qr);
}

int main()
{
    n=read(); m=read();
    for(ll i=1;i<=m;++i) g[read()].push_back(i);
    for(ll i=1;i<=n;++i) q[i].p=read(),q[i].id=i; k=read();
    for(ll i=1;i<=k;++i) L[i]=read(),R[i]=read(),val[i]=read();
    for(ll i=1;i<=k;++i) if(R[i]<L[i]) R[i]+=m; solve(1,k+1,1,n); 
    for(ll i=1;i<=n;++i)   
        if(ans[i]==k+1) puts("NIE");
        else printf("%lld\n",ans[i]);
    return 0;
}

posted @ 2019-03-25 20:52  cloud_9  阅读(96)  评论(0编辑  收藏  举报