数据结构杂题乱记

由于是杂题乱记所以题目大多数不会太难。

P2572 [SCOI2010] 序列操作

题目内容

给你一个 \(01\) 序列,支持 \(5\) 种操作:

  • 0 l r区间赋值为 \(0\)
  • 1 l r区间赋值为 \(1\)
  • 2 l r区间取反,即 \(0\)\(1\)\(1\)\(0\)
  • 3 l r询问区间 \(1\) 总数。
  • 4 l r询问区间最长 \(1\) 连续段长度。

思路

看到区间赋值,珂朵莉树板子题,然后翻看讨论区,发现珂朵莉树被Hack了,于是老老实实打线段树。同色连续段问题,对于每个节点开一个三元组,表示区间最长连续段长度,以区间左端点为左边界的最长连续段长度,以区间右端点为右边界的最长连续段长度。合并直接做即可。由于有区间翻转,所以再保存一个 \(0\) 的连续段三元组,更新时直接把 \(0,1\) 的三元组交换即可。注意如果左区间颜色完全一致,则父亲区间的左端点最长连续段长度为左区间的整体长度+右区间的左端点最长连续段长度。然后对于三个修改操作,分别记它们的 \(lazy\) 标记为 \(lazy0,lazy1,lazy2\),则有:

  • 如果当前操作为 \(0\)\(1\),则清空其余标记然后赋值。

  • 如果当前操作为 \(2\) 且该区间有 \(0\) 标记,删除 \(0\) 标记改为 \(1\) 标记,进行相应的赋值,不加 \(2\) 标记;有 \(1\) 标记同理。

  • 如果当前操作为 \(2\) 且该区间没有 \(0\)\(1\) 标记,则进行交换操作,然后对 \(2\) 标记取反,即无变为有、有变为无。

容易发现这样操作一个节点最多只会同时带有 \(1\) 种标记。无论是更新时的加标记还是pushdown都这么做就对了。然后这题就比较平凡了。为了直观,我把所有东西都分开写了,也许会有更简便的写法。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c[100001],u,v,w;
struct node
{
	int lid,rid,val;
	bool can;
	node operator +(const node &A)
	{
		register node rn;
		rn.val=max((*this).val,A.val);
		rn.val=max(rn.val,(*this).rid+A.lid);
		if((*this).can)
		{
			rn.lid=(*this).lid+A.lid;
		}
		else
		{
			rn.lid=(*this).lid;
		}
		if(A.can)
		{
			rn.rid=(*this).rid+A.rid;
		}
		else
		{
			rn.rid=A.rid;
		}
		rn.can=(*this).can&A.can;
		return rn;
	}
};
struct Segment_Tree
{
	#define N 400004
	int left[N],right[N],num2[N];
	bool lazy0[N],lazy1[N],lazy2[N];
	node num0[N],num1[N];
	il int ls(int x)
	{
		return x<<1;
	}
	il int rs(int x)
	{
		return x<<1|1;
	}
	il void pushup(int x)
	{
		num0[x]=num0[ls(x)]+num0[rs(x)];
		num1[x]=num1[ls(x)]+num1[rs(x)];
		num2[x]=num2[ls(x)]+num2[rs(x)];
	}
	il void pushdown(int x)
	{
		if(lazy0[x])
		{
			lazy0[x]=false;
			lazy1[ls(x)]=lazy2[ls(x)]=lazy1[rs(x)]=lazy2[rs(x)]=false;
			lazy0[ls(x)]=lazy0[rs(x)]=true;
			ri len=right[ls(x)]-left[ls(x)]+1;
			num0[ls(x)]={len,len,len,true};
			num1[ls(x)]={0,0,0,false};
			num2[ls(x)]=0;
			len=right[rs(x)]-left[rs(x)]+1;
			num0[rs(x)]={len,len,len,true};
			num1[rs(x)]={0,0,0,false};
			num2[rs(x)]=0;
		}
		if(lazy1[x])
		{
			lazy1[x]=false;
			lazy0[ls(x)]=lazy2[ls(x)]=lazy0[rs(x)]=lazy2[rs(x)]=false;
			lazy1[ls(x)]=lazy1[rs(x)]=true;
			ri len=right[ls(x)]-left[ls(x)]+1;
			num0[ls(x)]={0,0,0,false};
			num1[ls(x)]={len,len,len,true};
			num2[ls(x)]=len;
			len=right[rs(x)]-left[rs(x)]+1;
			num0[rs(x)]={0,0,0,false};
			num1[rs(x)]={len,len,len,true};
			num2[rs(x)]=len;
		}
		if(lazy2[x])
		{
			lazy2[x]=false;
			ri len=right[ls(x)]-left[ls(x)]+1;
			if(lazy0[ls(x)]||lazy1[ls(x)])
			{
				swap(lazy0[ls(x)],lazy1[ls(x)]);
				if(lazy0[ls(x)])
				{
					num0[ls(x)]={len,len,len,true};
					num1[ls(x)]={0,0,0,false};
					num2[ls(x)]=0;
				}
				else
				{
					num0[ls(x)]={0,0,0,false};
					num1[ls(x)]={len,len,len,true};
					num2[ls(x)]=len;
				}
			}
			else
			{
				num2[ls(x)]=len-num2[ls(x)];
				swap(num1[ls(x)],num0[ls(x)]);
				lazy2[ls(x)]^=1;
			}
			len=right[rs(x)]-left[rs(x)]+1;
			if(lazy0[rs(x)]||lazy1[rs(x)])
			{
				swap(lazy0[rs(x)],lazy1[rs(x)]);
				if(lazy0[rs(x)])
				{
					num0[rs(x)]={len,len,len,true};
					num1[rs(x)]={0,0,0,false};
					num2[rs(x)]=0;
				}
				else
				{
					num0[rs(x)]={0,0,0,false};
					num1[rs(x)]={len,len,len,true};
					num2[rs(x)]=len;
				}
			}
			else
			{
				num2[rs(x)]=len-num2[rs(x)];
				swap(num1[rs(x)],num0[rs(x)]);
				lazy2[rs(x)]^=1;
			}
		}
	}
	void build(int x,int lt,int rt)
	{
		left[x]=lt;
		right[x]=rt;
		if(left[x]==right[x])
		{
			if(c[lt])
			{
				num2[x]=1;
				num1[x]={1,1,1,true};
			}
			else
			{
				num0[x]={1,1,1,true};
			}
			return;
		}
		ri me=(lt+rt)>>1;
		build(ls(x),lt,me);
		build(rs(x),me+1,rt);
		pushup(x);
	}
	void add0(int x,int lt,int rt)
	{
		if(lt<=left[x]&&right[x]<=rt)
		{
			lazy1[x]=lazy2[x]=false;
			lazy0[x]=true;
			ri len=right[x]-left[x]+1;
			num0[x]={len,len,len,true};
			num1[x]={0,0,0,false};
			num2[x]=0;
			return;
		}
		pushdown(x);
		ri me=(left[x]+right[x])>>1;
		if(lt<=me)
		{
			add0(ls(x),lt,rt);
		}
		if(rt>me)
		{
			add0(rs(x),lt,rt);
		}
		pushup(x);
	}
	void add1(int x,int lt,int rt)
	{
		if(lt<=left[x]&&right[x]<=rt)
		{
			lazy0[x]=lazy2[x]=false;
			lazy1[x]=true;
			ri len=right[x]-left[x]+1;
			num0[x]={0,0,0,false};
			num1[x]={len,len,len,true};
			num2[x]=len;
			return;
		}
		pushdown(x);
		ri me=(left[x]+right[x])>>1;
		if(lt<=me)
		{
			add1(ls(x),lt,rt);
		}
		if(rt>me)
		{
			add1(rs(x),lt,rt);
		}
		pushup(x);
	}
	void add2(int x,int lt,int rt)
	{
		if(lt<=left[x]&&right[x]<=rt)
		{
			ri len=right[x]-left[x]+1;
			if(lazy0[x]||lazy1[x])
			{
				swap(lazy0[x],lazy1[x]);
				if(lazy0[x])
				{
					num0[x]={len,len,len,true};
					num1[x]={0,0,0,false};
					num2[x]=0;
				}
				else
				{
					num0[x]={0,0,0,false};
					num1[x]={len,len,len,true};
					num2[x]=len;
				}
			}
			else
			{
				num2[x]=len-num2[x];
				swap(num1[x],num0[x]);
				lazy2[x]^=1;
			}
			return;
		}
		pushdown(x);
		ri me=(left[x]+right[x])>>1;
		if(lt<=me)
		{
			add2(ls(x),lt,rt);
		}
		if(rt>me)
		{
			add2(rs(x),lt,rt);
		}
		pushup(x);
	}
	int find1(int x,int lt,int rt)
	{
		if(lt<=left[x]&&right[x]<=rt)
		{
			return num2[x];
		}
		pushdown(x);
		ri me=(left[x]+right[x])>>1,rn=0;
		if(lt<=me)
		{
			rn+=find1(ls(x),lt,rt);
		}
		if(rt>me)
		{
			rn+=find1(rs(x),lt,rt);
		}
		return rn;
	}
	node find2(int x,int lt,int rt)
	{
		if(lt<=left[x]&&right[x]<=rt)
		{
			return num1[x];
		}
		pushdown(x);
		ri me=(left[x]+right[x])>>1;
		register node rn1={-1,-1,-1},rn2={-1,-1,-1};
		if(lt<=me)
		{
			rn1=find2(ls(x),lt,rt);
		}
		if(rt>me)
		{
			rn2=find2(rs(x),lt,rt);
		}
		if(rn1.val>=0&&rn2.val>=0)
		{
			return rn1+rn2;
		}
		else
		{
			if(rn1.val>=0)
			{
				return rn1;
			}
			else
			{
				return rn2;
			}
		}
	}
	#undef N
}st;
int main()
{
	scanf("%d%d",&a,&b);
	for(ri i=1;i<=a;i++)
	{
		scanf("%d",&c[i]);
	}
	st.build(1,1,a);
	while(b--)
	{
		scanf("%d%d%d",&u,&v,&w);
		v++;
		w++;
		switch(u)
		{
			case 0:
			{
				st.add0(1,v,w);
				break;
			}
			case 1:
			{
				st.add1(1,v,w);
				break;
			}
			case 2:
			{
				st.add2(1,v,w);
				break;
			}
			case 3:
			{
				printf("%d\n",st.find1(1,v,w));
				break;
			}
			case 4:
			{
				printf("%d\n",st.find2(1,v,w).val);
				break;
			}
		}
	}
	return 0;
}
posted @ 2024-10-31 21:21  一位很会的教授er~  阅读(19)  评论(0编辑  收藏  举报