【BZOJ4631】踩气球 题解(线段树)

题目链接

----------------------

题目大意:给定一个长度为$n$的序列${a_i}$。现在有$m$个区间$[l_i,r_i]$和$q$个操作,每次选取一个$x$使得$a_x--$。问每一次操作后区间和为$0$的区间个数。

可以用主席树解决,但蒟蒻不会,蒟蒻只会写线段树QAQ。

对于每一个区间$[l_i,r_i]$,我们可以把它分解成线段树上$s$个区间,线段树每个结点维护一个向量数组,用来存包含它的区间。当某一个$a_x--$后,看线段树上区间和是否为0,如果是那么包含这个区间的区间$s--$。如果$s=0$那么$ans++$。

注意$update$向上回溯时也要判断一下是否为0,进行更新。

时间复杂度$O((m+q)\log n+n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,q,m,a[100005],ans;
struct node
{
    vector<int> v;
    int l,r,val;
}tree[500005];
struct Node
{
    int l,r,s;
}t[100005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void build(int index,int l,int r)
{
    tree[index].l=l;
    tree[index].r=r;
    if (l==r)
    {
        tree[index].val=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(index*2,l,mid);
    build(index*2+1,mid+1,r);
    tree[index].val=tree[index*2].val+tree[index*2+1].val;
}
inline void update(int index,int pos,int v)
{
    if (tree[index].l==tree[index].r)
    {
        tree[index].val+=v;
        if (tree[index].val==0)
        {
            for (int i=0;i<tree[index].v.size();i++)
            {
                t[tree[index].v[i]].s--;
                if (t[tree[index].v[i]].s==0) ans++;
            }
        }
        return;
    }
    int mid=(tree[index].l+tree[index].r)>>1;
    if (pos<=mid) update(index*2,pos,v);
    else update(index*2+1,pos,v);
    tree[index].val=tree[index*2].val+tree[index*2+1].val;
    if (tree[index].val==0)
    {
        for (int i=0;i<tree[index].v.size();i++)
        {
            t[tree[index].v[i]].s--;
            if (t[tree[index].v[i]].s==0) ans++;
        }
    }
}
inline void split(int index,int l,int r,int id)
{
    if (l<=tree[index].l&&tree[index].r<=r)
    {
        tree[index].v.push_back(id);
        t[id].s++;
        return;
    }
    int mid=(tree[index].l+tree[index].r)>>1;
    if (l<=mid) split(index*2,l,r,id);
    if (r>mid) split(index*2+1,l,r,id);
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    build(1,1,n);
    for (int i=1;i<=m;i++) t[i].l=read(),t[i].r=read();
    for (int i=1;i<=m;i++) split(1,t[i].l,t[i].r,i);
    q=read();
    while(q--)
    {
        int x=read();
        x=(x+ans-1)%n+1;
        update(1,x,-1);
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2020-07-19 19:53  我亦如此向往  阅读(151)  评论(0编辑  收藏  举报