hdu 3397 Sequence operation(区间合并)

博客探讨了区间合并问题,重点在于理解区间操作中可能的最大长度出现位置,包括端点及合并时的连续部分。文章强调了处理0、1和2不同类型操作时的策略,尤其是当0、1操作遇到2操作时的更新规则。此外,还介绍了如何利用结构体记录0和1的相关信息,以高效处理置反操作。
摘要由CSDN通过智能技术生成
题意:首先t表示有几组数据,然后n,m表示有n个数,m组操作,接着给你n个0或1的数字,,最后是操作0 a b表示把区间[a,b]里的数都变成0,1 a b把区间[a,b]里的数都变成1,2 a b表示把区间[a,b]里的1变成0,0变成1,3 a b表示[a,b]输出1的数目,4 a b表示输出最长的连续的1的数目。

区间合并的问题,因为最长的可能的除了可能出现在端点,还有可能出现在区间合并时,两边的连续的加起来。除了这个之外,还要注意,我们设置两个延迟标记,一个用来标记操作0、1,一个用来标记操作2,如果我们在进行操作0、1的更新的时候,如果有遇到操作2的标记,那么没必要往下更新标记2(因为会把操作2覆盖了),但是如果是进行操作2的更新,遇到操作0、1的更新,我们要往下更新。

        因为有涉及到将0变成1,将1变成0的操作,所以我们除了记录端点处连续的1的长度,区间内1的数目,区间内最长的连续的1的数目之外,我们还要记录关于0相同的信息,这样,当有置反操作的时候,我们简单地交换对应的0和1的信息就可以了。

/*代码风格更新后 */
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))
const int N=100005;

struct node
{
	int lft,rht;
	int lmx_0,rmx_0,mx_0,sum_0;
	int lmx_1,rmx_1,mx_1,sum_1;
	int flag_set,flag_rev;
	int len(){return rht-lft+1;}
	int mid(){return MID(lft,rht);}
	void set_0(int a){ lmx_0=rmx_0=mx_0=sum_0=a; }
	void set_1(int a){ lmx_1=rmx_1=mx_1=sum_1=a; }
	void init()
	{
		set_0(0); set_1(0);
		flag_rev=0; flag_set=-1;
	}
	void fun(int valu)
	{
		if(valu==0)
		{
			flag_set=0; flag_rev=0;
			set_0(len()); set_1(0);
		}
		else if(valu==1)
		{
			flag_set=1; flag_rev=0;
			set_0(0); set_1(len());
		}
		else 
		{
			swap(lmx_0,lmx_1);  swap(rmx_0,rmx_1);
			swap(mx_0,mx_1);	swap(sum_0,sum_1);
			flag_rev^=1;
		}
	}
};

int y[N],n,m;

struct Segtree
{
	node tree[N*4];
	void down(int ind)
	{
		if(tree[ind].flag_set!=-1)
		{
			tree[LL(ind)].fun(tree[ind].flag_set);
			tree[RR(ind)].fun(tree[ind].flag_set);
			tree[ind].flag_set=-1;
		}
		if(tree[ind].flag_rev)
		{
			tree[LL(ind)].fun(2);
			tree[RR(ind)].fun(2);
			tree[ind].flag_rev=0;
		}
	}
	void up(node &a,node &b,node &c)
	{
		a.lmx_0=b.lmx_0;  a.rmx_0=c.rmx_0;  
		a.lmx_1=b.lmx_1;  a.rmx_1=c.rmx_1;  
		a.sum_0=b.sum_0+c.sum_0;    a.sum_1=b.sum_1+c.sum_1;  
		a.mx_0=max(b.rmx_0+c.lmx_0,max(b.mx_0,c.mx_0));  
		a.mx_1=max(b.rmx_1+c.lmx_1,max(b.mx_1,c.mx_1));  
		if(b.len()==b.lmx_0) a.lmx_0+=c.lmx_0;  
		if(b.len()==b.lmx_1) a.lmx_1+=c.lmx_1;  
		if(c.len()==c.rmx_0) a.rmx_0+=b.rmx_0;  
		if(c.len()==c.rmx_1) a.rmx_1+=b.rmx_1;  
	}
	void build(int lft,int rht,int ind)
	{
		tree[ind].lft=lft;	tree[ind].rht=rht;
		tree[ind].init();
		if(lft==rht) 
		{
			if(y[lft]==1) tree[ind].set_0(0),tree[ind].set_1(1);
			else tree[ind].set_0(1),tree[ind].set_1(0);
		}
		else 
		{
			int mid=tree[ind].mid();
			build(lft,mid,LL(ind));
			build(mid+1,rht,RR(ind));
			up(tree[ind],tree[LL(ind)],tree[RR(ind)]);
		}
	}
	void updata(int st,int ed,int ind,int valu)
	{
		int lft=tree[ind].lft,rht=tree[ind].rht;
		if(st<=lft&&rht<=ed) tree[ind].fun(valu);
		else 
		{
			down(ind);
			int mid=tree[ind].mid();
			if(st<=mid) updata(st,ed,LL(ind),valu);
			if(ed> mid) updata(st,ed,RR(ind),valu);
			up(tree[ind],tree[LL(ind)],tree[RR(ind)]);
		}
	}
	int query(int st,int ed,int ind,int type)
	{
		int lft=tree[ind].lft,rht=tree[ind].rht;
		if(st<=lft&&rht<=ed) 
		{
			if(type==3) return tree[ind].sum_1;
			else return tree[ind].mx_1;
		}
		else 
		{
			down(ind);
			int mid=tree[ind].mid(),res;
			if(ed<=mid) res=query(st,ed,LL(ind),type);
			else if(st>mid) res=query(st,ed,RR(ind),type);
			else 
			{
				int tmp1=query(st,ed,LL(ind),type);
				int tmp2=query(st,ed,RR(ind),type);
				if(type==3) res=tmp1+tmp2;
				else 
				{
					int tmp3=min(tree[LL(ind)].rmx_1,tree[LL(ind)].rht-st+1);
					int tmp4=min(tree[RR(ind)].lmx_1,ed-tree[RR(ind)].lft+1);
					res=max(max(tmp1,tmp2),tmp3+tmp4);
				}
			}
			up(tree[ind],tree[LL(ind)],tree[RR(ind)]);
			return res;
		}	
	}
}seg;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++) scanf("%d",&y[i]);
		seg.build(0,n-1,1);
		for(int i=0;i<m;i++)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			if(a<=2) seg.updata(b,c,1,a);
			else printf("%d\n",seg.query(b,c,1,a));
		}
	}
	return 0;
}


/*代码风格更新前*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=100005;
int y[N];
struct node
{
    int left,right,co,flag;
    int maxl_0,maxr_0,maxl_1,maxr_1;
    int sum_0,sum_1,max_1,max_0;
    int mid(){return left+(right-left)/2;}
    int dis(){return right-left+1;}
    void change(int a,int rev)
    {
        if(a==0)
        {
            maxl_0=maxr_0=sum_0=max_0=dis();
            maxl_1=maxr_1=sum_1=max_1=0;
            co=a;   flag=0;
        }
        else if(a==1)
        {
            maxl_0=maxr_0=sum_0=max_0=0;
            maxl_1=maxr_1=sum_1=max_1=dis();
            co=a;   flag=0;
        }
        if(rev)
        {
            swap(maxr_1,maxr_0);    swap(maxl_0,maxl_1);
            swap(max_0,max_1);      swap(sum_0,sum_1);
            flag^=1;
        }
    }
};
void unin(node &a,node &b,node &c)
{
    a.maxl_0=b.maxl_0;  a.maxr_0=c.maxr_0;
    a.maxl_1=b.maxl_1;  a.maxr_1=c.maxr_1;
    a.sum_0=b.sum_0+c.sum_0;    a.sum_1=b.sum_1+c.sum_1;
    a.max_0=max(b.maxr_0+c.maxl_0,max(b.max_0,c.max_0));
    a.max_1=max(b.maxr_1+c.maxl_1,max(b.max_1,c.max_1));
    if(b.dis()==b.maxl_0) a.maxl_0+=c.maxl_0;
    if(b.dis()==b.maxl_1) a.maxl_1+=c.maxl_1;
    if(c.dis()==c.maxr_0) a.maxr_0+=b.maxr_0;
    if(c.dis()==c.maxr_1) a.maxr_1+=b.maxr_1;
}
struct Segtree
{
    node tree[N*4];
    void build(int left,int right,int r)
    {
        tree[r].left=left;  tree[r].right=right;
        tree[r].maxl_0=tree[r].maxr_0=tree[r].maxl_1=tree[r].maxr_1=0;
        tree[r].sum_0=tree[r].sum_1=tree[r].max_0=tree[r].max_1=0;
        tree[r].flag=0;     tree[r].co=-1;
        if(left==right)
        {
            tree[r].change(y[left],0);
        }
        else
        {
            int mid=tree[r].mid();
            build(left,mid,r*2);    build(mid+1,right,r*2+1);
            unin(tree[r],tree[r*2],tree[r*2+1]);
        }
    }
    void updata(int be,int end,int r,int co)
    {
        if(be<=tree[r].left&&tree[r].right<=end)
        {
            if(co==0||co==1) tree[r].change(co,0);
            else tree[r].change(-1,1);
        }
        else
        {
            if(tree[r].co!=-1||tree[r].flag)
            {
                tree[r*2].change(tree[r].co,tree[r].flag);
                tree[r*2+1].change(tree[r].co,tree[r].flag);
                tree[r].co=-1;  tree[r].flag=0;
            }
            int mid=tree[r].mid();
            if(be<=mid) updata(be,end,r*2,co);
            if(end>mid) updata(be,end,r*2+1,co);
            unin(tree[r],tree[r*2],tree[r*2+1]);
        }
    }
    int query(int be,int end,int r,int co)
    {
        if(be<=tree[r].left&&tree[r].right<=end)
        {
            if(co==3) return tree[r].sum_1;
            else return tree[r].max_1;
        }
        else
        {
            if(tree[r].co!=-1||tree[r].flag)
            {
                tree[r*2].change(tree[r].co,tree[r].flag);
                tree[r*2+1].change(tree[r].co,tree[r].flag);
                tree[r].co=-1;  tree[r].flag=0;
            }
            int mid=tree[r].mid();
            if(end<=mid) return query(be,end,r*2,co);
            else if(be>mid) return query(be,end,r*2+1,co);
            else
            {
                int max1=query(be,end,r*2,co);
                int max2=query(be,end,r*2+1,co);
                if(co==3) return max1+max2;
                int max3=min(tree[r*2].right-be+1,tree[r*2].maxr_1)+min(end-tree[r*2+1].left+1,tree[r*2+1].maxl_1);
                return max(max(max1,max2),max3);
            }
        }
    }
}seg;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&y[i]);
        seg.build(0,n-1,1);
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(a==0||a==1||a==2) seg.updata(b,c,1,a);
            else printf("%d\n",seg.query(b,c,1,a));
            //for(int j=0;j<n;j++) printf("%d ",seg.query(j,j,1,3)); puts("");
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值