POI2011 MET-Meteors

题目描述

题解:

第一道整体二分。

如果只有一个询问,我们可以二分答案,然后O(n)验证;

对于多种询问而且不强制在线,我们就可以使用整体二分。

整体二分的精髓是,先想一个二分暴力,然后把所有二分过程放在一起。

还有,整体二分中,分的是值域。

对于本题直接二分值域,然后将前$mid$个操作扔到树状数组/线段树中。

然后按能/不能完成二分。

到达底层,值域为$[l,l]$,我们就可以直接赋值了。

代码:

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300050
#define ll long long
const int inf = 0x3f3f3f3f;
inline int rd()
{
    int f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,m,k;
int ans[N],o[N];
vector<int>ve[N];
struct node
{
    int id;
    ll lim;
}p[N],tmpl[N],tmpr[N];
int tim;
struct BIT
{
    ll f[N];
    void up(int x,ll d)
    {
        if(!x)return ;
        while(x<N)f[x]+=d,x+=(x&-x);
    }
    ll down(int x)
    {
        if(!x)return 0;
        ll ret = 0;
        while(x)ret+=f[x],x-=(x&-x);
        return ret;
    }
}tr;
struct Stars
{
    int l,r,d;
}s[N];
void update(int l,int r,int d)
{
    if(l<=r)
    {
        tr.up(l,d);
        tr.up(r+1,-d);
    }else
    {
        tr.up(1,d),tr.up(r+1,-d);
        tr.up(l,d),tr.up(m+1,-d);
    }
}
void divi(int l,int r,int beg,int ens)
{
    if(beg>ens)return ;
    if(l==r)
    {
        for(int i=beg;i<=ens;i++)
            ans[p[i].id] = l;
        return ;
    }
    int mid = (l+r)>>1;
    while(tim<mid)tim++,update(s[tim].l,s[tim].r,s[tim].d);
    while(tim>mid)update(s[tim].l,s[tim].r,-s[tim].d),tim--;
    int lt=0,rt=0;
    for(int i=beg;i<=ens;i++)
    {
        ll sum = 0;
        for(int j=0;j<ve[p[i].id].size();j++)
        {
            sum+=tr.down(ve[p[i].id][j]);
            if(sum>=p[i].lim)break;
        }
        if(sum>=p[i].lim)tmpl[++lt]=p[i];
        else tmpr[++rt]=p[i];
    }
    for(int i=beg;i<=beg+lt-1;i++)p[i]=tmpl[i-beg+1];
    for(int i=beg+lt;i<=ens;i++)p[i]=tmpr[i-beg-lt+1];
    divi(l,mid,beg,beg+lt-1);
    divi(mid+1,r,beg+lt,ens);
}
int main()
{
    n = rd(),m = rd();
    for(int i=1;i<=m;i++)
    {
        o[i] = rd();
        ve[o[i]].push_back(i);
    }
    for(int i=1;i<=n;i++)
    {
        p[i].id = i;
        p[i].lim = rd();
    }
    k = rd();
    for(int i=1;i<=k;i++)
        s[i].l = rd(),s[i].r = rd(),s[i].d = rd();
    divi(1,k+1,1,n);
    for(int i=1;i<=n;i++)
    {
        if(ans[i]==k+1)puts("NIE");
        else printf("%d\n",ans[i]);
    }
    return 0;
}

 

posted @ 2018-12-31 09:23  LiGuanlin  阅读(99)  评论(0编辑  收藏  举报