洛谷 P5280 [ZJOI2019]线段树

洛谷 P5280 [ZJOI2019]线段树

https://www.luogu.com.cn/problem/P5280

UiMTPS.png

UiMH2Q.png

Tutorial

https://www.luogu.com.cn/blog/Sooke/solution-p5280

考虑一次修改中,每个节点的状态

(Sooke的图)

  1. dfs中经过的点(白)
  2. dfs的终点(黑)
  3. 白色的点的非黑白儿子(橙)
  4. 黑节点子树中的点(灰)
  5. 橙节点子树中的点(黄)

\(f(i,u)\)表示第\(i\)次修改后\(u\)节点在多少个线段树中的tag=1

首先对于所有点,在没有被修改的线段树中tag信息不会变化,接下来只考虑修改后的情况.

对于1类点,它的tag一定为0

对于2类点,它的tag一定为1

对于3类点,它的tag是否为1取决于它到根的路径上是否有节点的tag=1.

所有我们需要额外维护一个信息,设\(g(i,u)\)表示第\(i\)次修改后在多少个线段树中\(u\)到根的路径上的节点的tag都为0

(败者食尘)

对于1类点,它的tag一定为0,它到根的路径上的tag都为0

g[u]+=power(2,i-1);

对于2类点,它的tag一定为1

f[u]+=power(2,i-1);

对于3类点,它的tag是否为1取决于它到根的路径上是否有节点的tag=1

f[u]+=(power(2,i-1)-g[u]);
g[u]+=g[u];

对于4类点,它的tag不会变化,它到根的路径上一定有一个2类点tag=1

f[u]+=f[u]

对于5类点,它的tag不会变化,它到根的路径上是否有节点tag=1的情况不会变化

f[u]+=f[u];
g[u]+=g[u];

1,2,3类点的数量为\(O(\log n)\),可以在dfs过程中维护

4,5类点相当于将子树内的值全部乘2,可以用lazy标记维护

额外维护\(sf(u)\)表示\(u\)子树中\(f\)的和.询问答案为\(sf(1)\)

Code

#include <cstdio>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
using namespace std;
inline char gc() {
//	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
}
typedef long long ll;
const int mod=998244353;
const int maxn=1e5+50,maxm=1e5+50;
int n,m;
int cnt;
int pow2[maxm];
inline int add(int x) {return x>=mod?x-mod:x;}
inline int sub(int x) {return x<0?x+mod:x;}
namespace seg {
	const int maxnode=maxn<<3;
	int f[maxnode],sf[maxnode],tagf[maxnode];
	int g[maxnode],tagg[maxnode];
	inline void changeg(int u,int d) {
		g[u]=(ll)g[u]*d%mod;
		tagg[u]=(ll)tagg[u]*d%mod;
	}
	inline void changef(int u,int d) {
		f[u]=(ll)f[u]*d%mod,sf[u]=(ll)sf[u]*d%mod;
		tagf[u]=(ll)tagf[u]*d%mod; 
	}
	inline void pushdown(int u) {
		if(tagf[u]!=1) {
			changef(u<<1,tagf[u]);
			changef(u<<1|1,tagf[u]);
			tagf[u]=1;
		}
		if(tagg[u]!=1) {
			changeg(u<<1,tagg[u]);
			changeg(u<<1|1,tagg[u]);
			tagg[u]=1;
		}
	}
	inline void pushup(int u) {
		sf[u]=add(f[u]+add(sf[u<<1]+sf[u<<1|1]));
	}
	inline void change5(int u) {
		changef(u,2),changeg(u,2);
	}
	inline void change4(int u) {
		changef(u,2);
	}
	inline void change3(int u) {
		f[u]=add(sub(pow2[cnt-1]-g[u])+f[u]);
		g[u]=add(g[u]<<1);
		pushdown(u);
		change5(u<<1),change5(u<<1|1);
		pushup(u);
	}
	inline void change2(int u) {
		f[u]=add(pow2[cnt-1]+f[u]);
	}
	inline void change1(int u) {
		g[u]=add(pow2[cnt-1]+g[u]);
	}
	void build(int u,int l,int r) {
		g[u]=1;
		tagf[u]=tagg[u]=1;
		if(l==r) {
			return;
		}
		int mid=(l+r)>>1;
		build(lson);
		build(rson);
		pushup(u);
	}
	void update(int u,int l,int r,int ql,int qr) {
		if(l==ql&&r==qr) {
			change2(u);
			pushdown(u);
			change4(u<<1),change4(u<<1|1);
			pushup(u);
			return;
		}
		int mid=(l+r)>>1;
		change1(u);
		pushdown(u);
		if(qr<=mid) {
			change3(u<<1|1);
			update(lson,ql,qr);
		}
		else if(ql>mid) {
			change3(u<<1);
			update(rson,ql,qr);
		}
		else {
			update(lson,ql,mid);
			update(rson,mid+1,qr);
		}
		pushup(u);
	}
}
void init() {
	pow2[0]=1;
	for(int i=1;i<=m;++i) pow2[i]=add(pow2[i-1]<<1);
}
int main() {
	rd(n),rd(m);
	init();
	seg::build(1,1,n);
	for(int i=1;i<=m;++i) {
		int op; rd(op);
		if(op==1) {
			int l,r; rd(l),rd(r);
			++cnt,seg::update(1,1,n,l,r);
		}
		else {
			printf("%d\n",seg::sf[1]);
		}
	}
	return 0;
}
posted @ 2020-07-06 20:11  LJZ_C  阅读(83)  评论(0编辑  收藏  举报