• bzoj4631 踩气球


    题意:给定一个长为n的正整数序列,并给定m个区间,q次操作,每次操作将一个位置的数值减1,并在操作后输出给定的m个区间中有多少个区间的区间和为0.强制在线.

    数据范围:n,m,q<=10^5

    首先只有某个位置x的气球数目从1变成0的时候才会对答案产生影响,那么我们考虑这时什么样的区间的区间和会变成0.这样的区间之前一定包含位置x而且只有位置x不为0,也就是由位置x再加上x左边一段0和x右边一段0组成(这两段0可能不存在).我们找出x左边尽量长的一段连续的0和x右边尽量长的一段连续的0(这两段连续的0的长度可以用链表或者并查集维护,链表维护的方法见claris题解,我写的是无脑并查集).那么符合条件的区间的左端点在一个范围内,右端点在一个范围内,这种二维的查询就可以用主席树来做,按照左端点插入区间,将右端点对应的权值线段树可持久化就可以了.只有某个位置的数值变为0的时候才会在主席树上查询,复杂度为O(mlogn)建树+O(nlogn)查询.并查集还有个比较小的O(nlogn).

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    struct node{
      node* ch[2];
      int sum;
      node(){}
      node(int x){sum=x;ch[0]=ch[1]=0;}
    }t[maxn*50];int cnt=0;
    node* newnode(int x){
      t[++cnt]=node(x);return t+cnt;
    }
    node* root[maxn];
    int ufs[maxn],l[maxn],r[maxn];
    int find(int x){
      return ufs[x]==x?x:ufs[x]=find(ufs[x]);
    }
    void link(int a,int b){
      if(find(a)==find(b))return;
      int ra=find(a),rb=find(b);
      ufs[ra]=rb;l[rb]=min(l[rb],l[ra]);r[rb]=max(r[rb],l[rb]);
    }
    int a[maxn];
    vector<int> right[maxn];
    void Insert(node* rt0,node* &rt,int l,int r,int x){
      rt=newnode(rt0->sum+1);
      if(l==r)return;
      int mid=(l+r)>>1;
      if(x<=mid){
        Insert(rt0->ch[0],rt->ch[0],l,mid,  x);
        rt->ch[1]=rt0->ch[1];
      }else{
        Insert(rt0->ch[1],rt->ch[1],mid+1,r,x);
        rt->ch[0]=rt0->ch[0];
      }
    }
    int query(node* rt0,node* rt1,int l,int r,const int &ql,const int &qr){
      if(ql<=l&&r<=qr)return rt1->sum-rt0->sum;
      int mid=(l+r)>>1,ans=0;
      if(ql<=mid)ans+=query(rt0->ch[0],rt1->ch[0],l,mid,ql,qr);
      if(qr>mid) ans+=query(rt0->ch[1],rt1->ch[1],mid+1,r,ql,qr);
      return ans;
    }
    int main(){
      int n,m;scanf("%d%d",&n,&m);
      for(int i=1;i<=n;++i){
        ufs[i]=l[i]=r[i]=i;
      }
      for(int i=1;i<=n;++i)scanf("%d",&a[i]);
      int x,y;
      for(int i=1;i<=m;++i){
        scanf("%d%d",&x,&y);
        right[x].push_back(y);
      }
      root[0]=t;root[0]->ch[0]=root[0]->ch[1]=t;root[0]->sum=0;
      for(int i=1;i<=n;++i){
        root[i]=root[i-1];
        for(vector<int>::iterator pt=right[i].begin();pt!=right[i].end();++pt)Insert(root[i],root[i],1,n,*pt);
      }a[0]=a[n+1]=0x7f7f7f7f;
      int ans=0;
      int q;scanf("%d",&q);
      for(int i=1;i<=q;++i){
        scanf("%d",&x);x=(x+ans-1+n)%n+1;
        a[x]--;
        if(a[x]==0){
          int lo=x,hi=x;
          if(a[x-1]==0)lo=l[find(x-1)];
          if(a[x+1]==0)hi=r[find(x+1)];//printf("%d %d %d %d
    ",lo,x,x,hi);
          ans+=query(root[lo-1],root[x],1,n,x,hi);
          if(a[x-1]==0)link(x-1,x);
          if(a[x+1]==0)link(x,x+1);
        }
        printf("%d
    ",ans);
      }
      return 0;
    }
  • 相关阅读:
    mina:IoBuffer 常用方法(转载)
    js:对象之间的复制
    jquery与angular的交互
    javax.crypto.BadPaddingException: Given final block not properly padded
    jstree:重新加载数据集,刷新树
    TCP 握手 -> 微服务
    eclipse 中添加source
    02 IO
    为什么常用 Map<> map = new HashMap()
    自组织 Self-Orginaztion
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6537210.html
Copyright © 2020-2023  润新知