线段树(板子)

线段树

  • 单点修改,单点,区间查询
  • 区间修改,单点,区间查询

单点修改

普通线段树

code
#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define lll long long
const int N = 1000001;
int n,m;
int a[N];
struct T
{
	int l,r,data;
} tr[N<<2];
void pushup(int rt)
{
	tr[rt].data=tr[ls].data+tr[rs].data;
}
void bui(int rt,int l,int r)
{
	tr[rt].l=l; tr[rt].r=r;
	if(l==r)
	{
		tr[rt].data=a[l];
		return;//注意return
	}
	int mid=((lll)l+r)>>1;//注意long long
	bui(ls,l,mid); bui(rs,mid+1,r);
	pushup(rt);
}
void mdf(int rt,int x,int v)
{
	if(tr[rt].l==tr[rt].r)
	{
		tr[rt].data+=v;
		return;
	}
	int mid=((lll)tr[rt].l+tr[rt].r)>>1;
	if(x<=mid) mdf(ls,x,v);
	else mdf(rs,x,v);
	pushup(rt);
}
int que(int rt,int l,int r)
{
	if(l<=tr[rt].l&&r>=tr[rt].r)
		return tr[rt].data;
	int mid=((lll)tr[rt].l+tr[rt].r)>>1;
	int res=0;
	if(l<=mid) res+=que(ls,l,r);
	if(r>mid) res+=que(rs,l,r);
	return res;
}

区间修改

“卤煮”存一下更新,查询时再下放。

code
#define lll long long
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int N = 100005;
int n,a[N],m;
struct T
{
	int l,r,data,lz;
} tr[N<<2];
void pushup(int rt)
{
	tr[rt].data=tr[ls].data+tr[rs].data;
}
void pushdown(int rt)
{
	if(tr[rt].lz!=0)
	{
		int lz=tr[rt].lz;
		tr[rt].lz=0;
		tr[ls].lz+=lz;
		tr[rs].lz+=lz;
		tr[ls].data+=lz*(tr[ls].r-tr[ls].l+1);
		tr[rs].data+=lz*(tr[rs].r-tr[rs].l+1);
	}
}
void bui(int rt,int l,int r)
{
	tr[rt].l=l; tr[rt].r=r;
	if(l==r)
	{
		tr[rt].data=a[l];
		return ;
	}
	int mid=((lll)l+r)>>1;
	bui(ls,l,mid); bui(rs,mid+1,r);
	pushup(rt);
}
void mdf(int rt,int l,int r,int v)
{
	if(l<=tr[rt].l&&r>=tr[rt].r)
	{
		tr[rt].lz+=v;
		tr[rt].data+=v*(tr[rt].r-tr[rt].l+1);
		return;
	}
	pushdown(rt);//注意回溯
	int mid=((lll)tr[rt].l+tr[rt].r)>>1;
	if(l<=mid) mdf(ls,l,r,v);
	if(r>mid) mdf(rs,l,r,v);
	pushup(rt);
}
int que(int rt,int l,int r)
{
	if(l<=tr[rt].l&&r>=tr[rt].r)
		return tr[rt].data;
	pushdown(rt);
	int mid=((lll)tr[rt].l+tr[rt].r)>>1;
	int res=0;
	if(l<=mid) res+=que(ls,l,r);
	if(r>mid) res+=que(rs,l,r);
	return res;
}

线段树就是打心态。

补充

\(pushup\) 可以返回结构体,对于查询时需要进行合并操作的,还有返回多个数据的 很方便。

例一 Alternating String

大致题意:一个 \(0~1\) 序列,定义“好序列”为相邻两位不同(如:\(0~1~0~1\)\(1~0~1~0\))。
修改操作:区间 \(L~R\) \(0\)\(1\) ,\(1\)\(0\).
查询操作:区间 \(L~R\) 是否为“好”。

code
struct T
{
	int l,r,ld,rd,lz;
	bool ans;
} tr[N << 2];
T pushup(T r1,T r2)
{
	T tree;
	tree.l=r1.l; tree.r=r2.r;
	tree.ld=r1.ld; tree.rd=r2.rd;
	tree.lz=0;
	if(r1.ans&&r2.ans)
	{
		if(r1.rd!=r2.ld) tree.ans=1;
		else tree.ans=0;
	}
	else tree.ans=0;
	return tree;
}
void pushdown(int rt)
{
	if(tr[rt].lz) 
	{
		tr[rt].lz = 0;
		tr[ls].lz ^= 1;	tr[rs].lz ^= 1;
		tr[ls].ld ^= 1;	tr[rs].rd ^= 1;
		tr[rs].ld ^= 1;	tr[ls].rd ^= 1;
	}	
}
void bui(int rt,int l,int r)
{
	tr[rt].l=l; tr[rt].r=r;
	if(l==r)
	{
		tr[rt].ans=1;
		tr[rt].ld=tr[rt].rd=a[l];
		return;
	}
	int mid=(l+r)>>1;
	bui(ls,l,mid); bui(rs,mid+1,r);
	int flag=tr[rt].lz;//“卤煮”处理的不太好,因为不能从下向上回溯。所以额外存一下。
	tr[rt]=pushup(tr[ls],tr[rs]);
	tr[rt].lz=flag;
}
void mdf(int rt,int l,int r)
{
	if(l<=tr[rt].l&&r>=tr[rt].r)
	{
		tr[rt].lz ^= 1;
		tr[rt].ld ^= 1;
		tr[rt].rd ^= 1;
		return;
	}
    pushdown(rt);
	int mid=(tr[rt].l+tr[rt].r)>>1;
	if(l<=mid) mdf(ls,l,r);
	if(r>mid) mdf(rs,l,r);
	int flag=tr[rt].lz;
	tr[rt]=pushup(tr[ls],tr[rs]);
	tr[rt].lz=flag;
}
T que(int rt,int l,int r)
{
	if(l<=tr[rt].l&&r>=tr[rt].r)
		return tr[rt];
	pushdown(rt);
	int mid=(tr[rt].l+tr[rt].r)>>1;
	if(r<=mid) return que(ls,l,r);
	if(mid<l) return que(rs,l,r);
	return pushup(que(ls,l,r),que(rs,l,r));
}
例二 山海经
posted @ 2024-02-19 17:59  ppllxx_9G  阅读(21)  评论(0编辑  收藏  举报