• LOJ 2302 「NOI2017」整数——压位线段树


    题目:https://loj.ac/problem/2302

    压30位,a最多落在两个位置上,拆成两次操作。

    该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 1 / 0 的那个位置上 -1 或者 +1 。

    注意是在那个位置上 -1 或者 +1 而不是 -lowbit 或者 +lowbit 。

    询问都是 <=30n ,所以只维护 30n 的范围即可。注意线段树压 30 位,开 n 个位置恰好是 0*n ~ 29*n,所以开 n+1 个位置。

    线段树只需维护自己区间是全 0 / 1 还是都有。找连续一段 0/1 就在线段树上二分即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ls Ls[cr]
    #define rs Rs[cr]
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    const int N=2e6+5,bs=30;
    int n,nr,tot,Ls[N],Rs[N],lx[N],vl[N],tg[N];
    int bin[bs+5],U;  bool fx;
    void build(int l,int r,int cr)
    {
      tg[cr]=-1; lx[cr]=vl[cr]=0;
      if(l==r)return; int mid=l+r>>1;
      ls=++tot; build(l,mid,ls);
      rs=++tot; build(mid+1,r,rs);
    }
    void pshd(int cr)
    {
      if(tg[cr]==-1)return; int k=tg[cr]; tg[cr]=-1;
      tg[ls]=tg[rs]=k;
      if(k==1){ vl[ls]=vl[rs]=U; lx[ls]=lx[rs]=1;}
      else { vl[ls]=vl[rs]=0; lx[ls]=lx[rs]=0;}
    }
    void pshp(int cr)
    {
      if((!lx[ls])&&(!lx[rs]))lx[cr]=0;
      else if(lx[ls]==1&&lx[rs]==1)lx[cr]=1; else lx[cr]=2;
    }
    void updt(int cr)
    { if(!vl[cr])lx[cr]=0; else if(vl[cr]==U)lx[cr]=1; else lx[cr]=2;}
    int fnd(int l,int r,int cr,int L,int R,int k)
    {
      if(l>=L&&r<=R)
        {
          if(lx[cr]==(!k))return nr+1; if(l==r)return l;
          int mid=l+r>>1; pshd(cr);
          if(lx[ls]!=(!k))return fnd(l,mid,ls,L,R,k);
          return fnd(mid+1,r,rs,L,R,k);
        }
      int mid=l+r>>1,d=nr+1; pshd(cr);
      if(L<=mid)d=fnd(l,mid,ls,L,R,k);
      if(d==nr+1)d=fnd(mid+1,r,rs,L,R,k);
      return d;
    }
    void mdfy(int l,int r,int cr,int L,int R,int k)
    {
      if(l>=L&&r<=R)
        {
          tg[cr]=k; if(k==1){vl[cr]=U;lx[cr]=1;}
          else {vl[cr]=0;lx[cr]=0;} return;
        }
      int mid=l+r>>1; pshd(cr);
      if(L<=mid)mdfy(l,mid,ls,L,R,k);
      if(mid<R)mdfy(mid+1,r,rs,L,R,k);
      pshp(cr);
    }
    void mdfy2(int l,int r,int cr,int p,int k)
    {
      if(l==r)
        {
          if(k==1)vl[cr]++; else vl[cr]--;/////
          /*if(k==1){ int tmp=(vl[cr]^U); vl[cr]+=(tmp&(-tmp));}
        else vl[cr]-=(vl[cr]&(-vl[cr]));*/
          updt(cr); return;
        }
      int mid=l+r>>1; pshd(cr);
      if(p<=mid)mdfy2(l,mid,ls,p,k);
      else mdfy2(mid+1,r,rs,p,k);
      pshp(cr);
    }
    void add(int p)
    {
      int d=fnd(1,nr,1,p,nr,0);//fnd first 0
      if(p<d)mdfy(1,nr,1,p,d-1,0);
      if(d<=nr)mdfy2(1,nr,1,d,1);//chg 0 to 1
    }
    void dec(int p)
    {
      int d=fnd(1,nr,1,p,nr,1);
      if(p<d)mdfy(1,nr,1,p,d-1,1);
      if(d<=nr)mdfy2(1,nr,1,d,0);
    }
    void solve(int l,int r,int cr,int p,int k)
    {
      if(l==r)
        {
          if(!fx)vl[cr]+=k; else vl[cr]-=k;
          if(vl[cr]>=bin[bs]){ vl[cr]-=bin[bs];add(l+1);}
          if(vl[cr]<0){ vl[cr]+=bin[bs];dec(l+1);}
          updt(cr); return;
        }
      int mid=l+r>>1; pshd(cr);
      if(p<=mid)solve(l,mid,ls,p,k); else solve(mid+1,r,rs,p,k);
      pshp(cr);
    }
    bool qry(int l,int r,int cr,int p,int p2)
    {
      if(l==r)return vl[cr]&bin[p2];
      int mid=l+r>>1; pshd(cr);
      if(p<=mid)return qry(l,mid,ls,p,p2);
      else return qry(mid+1,r,rs,p,p2);
    }
    int main()
    {
      n=rdn(); nr=n+1; int tp=rdn();tp=rdn();tp=rdn();
      bin[0]=1;for(int i=1;i<=bs;i++)bin[i]=bin[i-1]<<1;
      U=bin[bs]-1; tot=1;build(1,nr,1);
      for(int i=1,op,a,b,l,r;i<=n;i++)
        {
          op=rdn();
          if(op==1)
        {
          a=rdn();b=rdn(); l=b; r=b+bs-1;
          l=l/bs+1; r=r/bs+1;
          if(a<0)a=-a,fx=1; else fx=0;
          if(l<r)
            {
              int k=a&(bin[l*bs-b]-1);
              a>>=(l*bs-b); k<<=(b-(l-1)*bs);
              solve(1,nr,1,l,k); solve(1,nr,1,r,a);
            }
          else solve(1,nr,1,l,a);
        }
          else
        {
          a=rdn(); l=a/bs+1; a-=(l-1)*bs;
          printf("%d
    ",qry(1,nr,1,l,a));
        }
        }
      return 0;
    }
  • 相关阅读:
    python之enumerate
    Python中的集合set
    SGU 分类
    太空飞行计划 最大权闭合图
    1.飞行员配对 二分图匹配(输出方案)/最大流斩
    poj1149最大流经典构图神题
    hdu1569 方格取数 求最大点权独立集
    最大独立集 最小点覆盖 最小边覆盖 最小路径覆盖 最大团
    hdu3491最小割转最大流+拆点
    hdu3987,最小割时求最少割边数
  • 原文地址:https://www.cnblogs.com/Narh/p/10972731.html
Copyright © 2020-2023  润新知