bzoj 4592(洛谷 4344) [Shoi2015]脑洞治疗仪——线段树上二分

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4592

1操作就是用线段树来二分找到第一个有 k 个0的位置。

在洛谷上A了,与暴力和网上题解对拍也都没问题。在bzoj上4msWA。不知道为什么。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
const int N=2e5+5,M=N<<1;
int n,m,sm[M],fl[M],fr[M],mx[M],Ls[M],Rs[M],lz[M],tot;
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<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
void build(int l,int r,int cr)
{
  sm[cr]=r-l+1; lz[cr]=-1; 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,int l,int mid,int r)
{
  if(lz[cr]==-1)return;
  fl[ls]=fr[ls]=mx[ls]=(lz[cr]?0:mid-l+1); sm[ls]=(lz[cr]?mid-l+1:0);
  fl[rs]=fr[rs]=mx[rs]=(lz[cr]?0:r-mid); sm[rs]=(lz[cr]?r-mid:0);
  lz[ls]=lz[rs]=lz[cr]; lz[cr]=-1;
}
void pshp(int cr)
{
  sm[cr]=sm[ls]+sm[rs];
  fl[cr]=fl[ls]+(sm[ls]?0:fl[rs]);
  fr[cr]=fr[rs]+(sm[rs]?0:fr[ls]);
  mx[cr]=max(max(fl[cr],fr[cr]),max(mx[ls],mx[rs]));
  mx[cr]=max(mx[cr],fr[ls]+fl[rs]);
}
void mdfy(int l,int r,int cr,int L,int R,bool k)
{
  if(l>=L&&r<=R)
    {
      fl[cr]=fr[cr]=mx[cr]=(k?0:r-l+1); sm[cr]=(k?r-l+1:0);
      lz[cr]=k; return;
    }
  int mid=l+r>>1; pshd(cr,l,mid,r);
  if(L<=mid)mdfy(l,mid,ls,L,R,k);
  if(mid<R)mdfy(mid+1,r,rs,L,R,k);
  pshp(cr);
}
int qry(int l,int r,int cr,int L,int R)
{
  if(l>=L&&r<=R) return sm[cr];
  int mid=l+r>>1,ret=0; pshd(cr,l,mid,r);
  if(L<=mid) ret=qry(l,mid,ls,L,R);
  if(mid<R) ret+=qry(mid+1,r,rs,L,R);
  return ret;
}
int fnd(int l,int r,int cr,int L,int R,int k)
{
  if(l==r)return l;
  int mid=l+r>>1; pshd(cr,l,mid,r);
  if(l>=L&&r<=R)
    {
      int siz=mid-l+1-sm[ls];
      if(siz>=k)return fnd(l,mid,ls,L,R,k);
      return fnd(mid+1,r,rs,L,R,k-siz);
    }
  if(mid<L)return fnd(mid+1,r,rs,L,R,k);
  if(R<=mid)return fnd(l,mid,ls,L,R,k);
  int d=qry(l,mid,ls,L,R);
  d=mid-max(l,L)+1-d;//L!!!!//max!!!!!probably just r>R
  if(d>=k) return fnd(l,mid,ls,L,R,k);
  return fnd(mid+1,r,rs,L,R,k-d);
}
int query(int l,int r,int cr,int L,int R)
{
  if(l>=L&&r<=R)return mx[cr];
  int mid=l+r>>1; pshd(cr,l,mid,r);
  if(mid<L) return query(mid+1,r,rs,L,R);
  if(R<=mid) return query(l,mid,ls,L,R);
  int ret=max(query(l,mid,ls,L,R),query(mid+1,r,rs,L,R));
  ret=max(ret,min(fr[ls],mid-L+1)+min(fl[rs],R-mid));/////
}
void print()
{
  for(int i=1;i<=n;i++)
    printf("%d ",qry(1,n,1,i,i));
  puts("");
}
int main()
{
  n=rdn(); m=rdn(); tot=1; build(1,n,1);
  for(int i=1,op,l,r,l1,r1,d,k;i<=m;i++)
    {
      op=rdn(); l=rdn(); r=rdn();
      if(!op)
    {
      mdfy(1,n,1,l,r,0);
    }
      if(op==1)
    {
      l1=rdn(); r1=rdn();
      d=qry(1,n,1,l,r); if(!d)continue;
      mdfy(1,n,1,l,r,0);  k=qry(1,n,1,l1,r1);
      if(r1-l1+1-k<=d) mdfy(1,n,1,l1,r1,1);
      else
        {
          k=fnd(1,n,1,l1,r1,d);
          mdfy(1,n,1,l1,k,1);
        }
    }
      if(op==2)
    {
      printf("%d\n",query(1,n,1,l,r));
    }
    }
  return 0;
}

附上暴力和maker和对拍,以便之后查。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int n,m,ans;
bool a[N];
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<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
int main()
{
  n=rdn(); m=rdn(); for(int i=1;i<=n;i++)a[i]=1;
  for(int i=1,op,l,r,l1,r1,d;i<=m;i++)
    {
      op=rdn(); l=rdn(); r=rdn();
      if(!op)
    {
      for(int j=l;j<=r;j++)a[j]=0;
    }
      if(op==1)
    {
      l1=rdn(); r1=rdn(); d=0;
      for(int j=l;j<=r;j++)d+=a[j],a[j]=0;
      for(int j=l1;j<=r1&&d;j++)
        d-=(!a[j]),a[j]=1;
    }
      if(op==2)
    {
      d=0; ans=0;
      for(int j=l;j<=r;j++)
          if(!a[j])d++;
          else ans=max(ans,d),d=0;
      ans=max(ans,d);
      printf("%d\n",ans);
    }
    }
  return 0;
}
暴力
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=2e5,M=10;
int n,m,op,l,r;
int main()
{
  srand(time(0));
  n=rand()%N+1; m=rand()%N+1;
  printf("%d %d\n",n,m);
  for(int i=1;i<=m;i++)
    {
      op=rand()%M;
      if(op>=3)op=2;
      l=rand()%n+1; r=rand()%n+1;
      if(l>r)swap(l,r);
      if(op==1)
    {
      printf("%d %d %d ",op,l,r);
      l=rand()%n+1; r=rand()%n+1;
      if(l>r)swap(l,r);
      printf("%d %d\n",l,r);
    }
      else printf("%d %d %d\n",op,l,r);
    }
  return 0;
}
maker
#include<cstdio>
#include<algorithm>
using namespace std;
int cnt;
int main()
{
  while(1)
    {
      system("./maker > data.in");
      system("./a < data.in > zj.out");
      system("./b < data.in > bl.out");
      if(system("diff zj.out bl.out"))return 0;
      cnt++; printf("cnt=%d\n",cnt);
      if(cnt==500)return 0;
    }
}
对拍

 

转载于:https://www.cnblogs.com/Narh/p/9868239.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值