您的位置:首页 > 产品设计 > UI/UE

hdu 3397 Sequence operation(线段树的延迟标记)

2013-01-18 13:01 711 查看
做这道题之前建议先做:hdu 3911是这道题的一部分,这是我的博客链接:/article/6394105.html

题意:首先给出一组数据:由0和1组成,然后有5种操作,0 a b表示把[a,b]区间的数全部变成0;1 a b 表示把[a,b]区间的数全部变成1;2 a b表示把[a,b]区间的0变成1、1变成0,也就是进行异或操作;3 a b就是问你[a,b]区间总共有多少个1,;4 a b就是问你[a,b]区间最长的连续的1的个数。

代码实现:

#include<iostream>
using namespace std;
struct node{
int l,r;
int lone,lzero;//分别是从左数1的个数和0的个数
int rone,rzero;//分别是从右数1的个数和0的个数
int max1,max0;//分别是连续的最多的1的个数和连续的最长0的个数
int total1,flag0,flag1,flag2,mlen;//分别是总共1的个数、是否进行了0操作,1操作,2操作的标记
}p[1000001];//这里有点坑开了100001*4的大小一直是Runtime erroy
int a[1000001];
int max(int x,int y)
{
return x>y?x:y;
}
int min(int x,int y)
{
return x<y?x:y;
}
void pushup(int n)//往上更新
{
p
.lone=p[n*2].lone;
if(p[n*2].lone==p[n*2].mlen)
p
.lone+=p[n*2+1].lone;
p
.lzero=p[n*2].lzero;
if(p[n*2].lzero==p[n*2].mlen)//左右子树可以合并
p
.lzero+=p[n*2+1].lzero;
p
.rone=p[n*2+1].rone;
if(p[n*2+1].rone==p[n*2+1].mlen)//左右子树可以合并
p
.rone+=p[n*2].rone;
p
.rzero=p[n*2+1].rzero;
if(p[n*2+1].rzero==p[n*2+1].mlen)//左右子树可以合并
p
.rzero+=p[n*2].rzero;
p
.max1=max(p[n*2].max1,p[n*2+1].max1);
p
.max1=max(p
.max1,p[n*2].rone+p[n*2+1].lone);
p
.max0=max(p[n*2].max0,p[n*2+1].max0);
p
.max0=max(p
.max0,p[n*2].rzero+p[n*2+1].lzero);
p
.total1=p[n*2].total1+p[n*2+1].total1;
}
void build(int l,int r,int n)//建立线段树
{
p
.l=l;
p
.r=r;
p
.flag0=p
.flag1=p
.flag2=0;
p
.mlen=(r-l+1);
if(l==r)
{
if(a[l]==1)
{
p
.total1=1;
p
.lone=1;
p
.lzero=0;
p
.rone=1;
p
.rzero=0;
p
.max1=1;
p
.max0=0;
}
else
{
p
.total1=0;
p
.lone=0;
p
.lzero=1;
p
.rone=0;
p
.rzero=1;
p
.max1=0;
p
.max0=1;
}
return ;
}
int mid=(l+r)/2;
build(l,mid,n*2);
build(mid+1,r,n*2+1);
pushup(n);//往上更新
}
void pushdown(int n,int flag)//往下更新
{
if(flag==0)
{
p[n*2].flag0=p[n*2+1].flag0=1;
p[n*2].flag1=p[n*2].flag2=0;//flag1和flag2不管以前是0还是1全部变成0
p[n*2+1].flag1=p[n*2+1].flag2=0;
p
.flag0=0;
p[n*2].total1=0;
p[n*2].lone=0;
p[n*2].lzero=p[n*2].mlen;
p[n*2].rone=0;
p[n*2].rzero=p[n*2].mlen;
p[n*2].max1=0;
p[n*2].max0=p[n*2].mlen;

p[n*2+1].total1=0;
p[n*2+1].lone=0;
p[n*2+1].lzero=p[n*2+1].mlen;
p[n*2+1].rone=0;
p[n*2+1].rzero=p[n*2+1].mlen;
p[n*2+1].max1=0;
p[n*2+1].max0=p[n*2+1].mlen;
}
else if(flag==1)
{
p[n*2].flag1=p[n*2+1].flag1=1;
p[n*2].flag0=p[n*2].flag2=0;//flag0和flag2不管以前是0还是1全部变成0
p[n*2+1].flag0=p[n*2+1].flag2=0;
p
.flag1=0;
p[n*2].total1=p[n*2].mlen;
p[n*2].lone=p[n*2].mlen;
p[n*2].lzero=0;
p[n*2].rone=p[n*2].mlen;
p[n*2].rzero=0;
p[n*2].max1=p[n*2].mlen;
p[n*2].max0=0;

p[n*2+1].total1=p[n*2+1].mlen;
p[n*2+1].lone=p[n*2+1].mlen;
p[n*2+1].lzero=0;
p[n*2+1].rone=p[n*2+1].mlen;
p[n*2+1].rzero=0;
p[n*2+1].max1=p[n*2+1].mlen;
p[n*2+1].max0=0;
}
else
{
p[n*2].flag2^=1;
p[n*2+1].flag2^=1;
p
.flag2=0;
swap(p[n*2].lone,p[n*2].lzero);
swap(p[n*2].rone,p[n*2].rzero);
swap(p[n*2].max1,p[n*2].max0);
p[n*2].total1=p[n*2].mlen-p[n*2].total1;

swap(p[n*2+1].lone,p[n*2+1].lzero);
swap(p[n*2+1].rone,p[n*2+1].rzero);
swap(p[n*2+1].max1,p[n*2+1].max0);
p[n*2+1].total1=p[n*2+1].mlen-p[n*2+1].total1;
}
}
void insert(int x,int y,int n,int nima)//更新
{
if(x==p
.l&&p
.r==y)
{
if(nima==0)
{
p
.flag0=1;
p
.flag1=0;
p
.flag2=0;
p
.lone=0;
p
.lzero=p
.mlen;
p
.rone=0;
p
.rzero=p
.mlen;
p
.max1=0;
p
.max0=p
.mlen;
p
.total1=0;
return ;
}
else if(nima==1)
{
p
.flag1=1;
p
.flag0=0;
p
.flag2=0;
p
.lone=p
.mlen;
p
.lzero=0;
p
.rone=p
.mlen;
p
.rzero=0;
p
.max1=p
.mlen;
p
.max0=0;
p
.total1=p
.mlen;
return ;
}
else//如果是异或的话,先判断下flag0和flag1是0还是1
{
p
.flag2=p
.flag2^1;
if(p
.flag0==1)//是1的话先往下更新
pushdown(n,0);
if(p
.flag1==1)//是1的话先往下更新
pushdown(n,1);
swap(p
.lone,p
.lzero);
swap(p
.rone,p
.rzero);
swap(p
.max1,p
.max0);
p
.total1=p
.mlen-p
.total1;
return ;
}
}
if(p
.l!=p
.r)
{
if(p
.flag0==1)
pushdown(n,0);
if(p
.flag1==1)
pushdown(n,1);
if(p
.flag2==1)
pushdown(n,2);
}
int mid=(p
.l+p
.r)/2;
if(y<=mid)
insert(x,y,n*2,nima);
else if(x>mid)
insert(x,y,n*2+1,nima);
else
{
insert(x,mid,n*2,nima);
insert(mid+1,y,n*2+1,nima);
}
pushup(n);
}
int sum1(int x,int y,int n)//求区间总共有多少个1
{
if(p
.mlen==p
.max1)
return y-x+1;
if(p
.mlen==p
.max0)
return 0;
if(x==p
.l&&y==p
.r)
return p
.total1;
if(p
.l!=p
.r)
{
if(p
.flag0==1)
pushdown(n,0);
if(p
.flag1==1)
pushdown(n,1);
if(p
.flag2==1)
pushdown(n,2);
}
int mid=(p
.l+p
.r)/2;
if(y<=mid)
sum1(x,y,n*2);
else if(x>mid)
sum1(x,y,n*2+1);
else
return sum1(x,mid,n*2)+sum1(mid+1,y,n*2+1);
}
int sum2(int x,int y,int n)//求区间连续1的最长的个数
{
if(p
.mlen==p
.max1)
return y-x+1;
if(p
.mlen==p
.max0)
return 0;
if(x==p
.l&&y==p
.r)
return p
.max1;
if(p
.l!=p
.r)
{
if(p
.flag0==1)
pushdown(n,0);
if(p
.flag1==1)
pushdown(n,1);
if(p
.flag2==1)
pushdown(n,2);
}
int mid=(p
.l+p
.r)/2;
if(y<=mid)
return sum2(x,y,n*2);
else if(x>mid)
return sum2(x,y,n*2+1);
else
{
int left=0,right=0,midden=0;
midden=midden+min(mid-x+1,p[n*2].rone)+min(y-mid,p[n*2+1].lone);
left=sum2(x,mid,n*2);
right=sum2(mid+1,y,n*2+1);
return max(midden,max(left,right));
}
}
int main()
{
int T,n,m,i,nima,x,y;
while(scanf("%d",&T)!=EOF)
{
while(T--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
while(m--)
{
scanf("%d%d%d",&nima,&x,&y);
switch(nima)
{
case 0:
insert(x+1,y+1,1,nima);break;
case 1:
insert(x+1,y+1,1,nima);break;
case 2:
insert(x+1,y+1,1,nima);break;
case 3:
printf("%d\n",sum1(x+1,y+1,1));break;
case 4:
printf("%d\n",sum2(x+1,y+1,1));break;
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: