zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Neo4j图形数据库备份
    Linux中Tomcat 自动设置CATALINA_HOME方法
    VNC viewer 无法打开oracle 11g图形界面方案
    CYPHER 语句(Neo4j)
    Tomcat部署时war和war exploded区别
    java中不能使用小数点(.)来作为分隔符
    做一个完整的Java Web项目需要掌握的技能
    从零讲Java,给你一条清晰地学习道路!该学什么就学什么!
    MYSQL数据库表排序规则不一致导致联表查询,索引不起作用问题
    chrome浏览器的跨域设置——包括版本49前后两种设置
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13340975.html
Copyright © 2011-2022 走看看