你说得对,但我是宫司大人的狗!

洛谷

题目传送门

上次校内模拟赛的 DS 题写分块被卡爽了,所以这集我们写线段树。

一开始半小时码出来然后一遍过样例,但一直 WA;后面怒调非常久才过。我太菜了。

分析

前两种操作就是线段树板子,所以重点考虑第三种操作。

显然,对于前两种操作,如果它们被撤销了,那我们就白做了。所以想到维护一个标记数组 \(f\),其中 \(f_i\) 表示第 \(i\) 个时刻的操作会不会被撤销。对于每个操作,如果 \(f_i\) 为真,我们就直接跳过。

同时我们发现,位置靠后的撤销操作可以撤销位置靠前的撤销操作,而位置靠前的撤销操作则不可以。于是我们可以按时刻从大到小的顺序执行所有撤销操作。对于每一次撤销操作,如果它对应的时刻已经被撤销了,那我们就跳过它;否则将它对应的区间中所有 \(f_i\) 推平为真。这一过程可以用线段树来做。

接下来就很好做了。我们使用两棵线段树,一棵维护原序列,一棵维护 \(f\)。前者先把树建出来,执行区间加、区间求最大值的操作;后者可以动态开点,执行区间推平、单点求值的操作。

于是这题就做完了。

代码

码风魔怔,欢迎来喷。

#include<iostream>
#include<vector>
#include<algorithm>
#include<bitset>
#define ll long long
using namespace std;

const int N=3e6+5;

int n,m;
int tot/*要离散化的数的总数*/;ll tott/*t 的离散化后的值域*/;

int a[N];
ll b[N<<2];
bitset<N>flag/*flag[i] -> 编号为 i 的操作有没有被撤销*/;
vector<ll>ans;

struct opt{
	int op,id;
	ll t,l,r,k;
}qu[N];

namespace OIfast{
	
	char buf[1<<21],*p1,*p2,*top,buffer[1<<21];
	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?0:*p1++)
	#define gc getchar()
	
	inline ll read(){
		ll n=0,f=1;static char c=gc;
		while(!isdigit(c)){if(c=='-')f=-1;c=gc;}
		while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
		return n*f;
	}
	
}using namespace OIfast;

namespace segmentTree{//维护原序列
	
	#define ls u<<1
	#define rs u<<1|1
	#define mid (L+R>>1)
	
	ll la[N<<2],mx[N<<2];
	
	inline ll maxx(ll a,ll b){
		return a>b?a:b;
	}
	
	inline void getmx(ll &a,ll b){
		return a=maxx(a,b),void();
	}
	
	inline void pushup(int u){
		return mx[u]=maxx(mx[ls],mx[rs]),void();
	}
	
	inline void pushdown(int u){
		if(!la[u])return ;
		return la[ls]+=la[u],la[rs]+=la[u],mx[ls]+=la[u],mx[rs]+=la[u],la[u]=0,void();
	}
	
	inline void build(int u,int L,int R){
		if(L==R)return mx[u]=a[L],void();
		return build(ls,L,mid),build(rs,mid+1,R),pushup(u),void();
	}
	
	inline void upd(int u,int l,int r,ll v,int L,int R){
		if(L>r||l>R)return ;
		if(l<=L&&R<=r)return la[u]+=v,mx[u]+=v,void();
		pushdown(u);
		if(l<=mid)upd(ls,l,r,v,L,mid);
		if(r>mid)upd(rs,l,r,v,mid+1,R);
		return pushup(u),void();
	}
	
	inline ll qry(int u,int l,int r,int L,int R){
		if(L>r||l>R)return -1e18;
		if(l<=L&&R<=r)return mx[u];
		ll res=-1e18;pushdown(u);
		if(l<=mid)getmx(res,qry(ls,l,r,L,mid));
		if(r>mid)getmx(res,qry(rs,l,r,mid+1,R));
		return res;
	}
	
	#undef ls
	#undef rs
	#undef mid
	
}using namespace segmentTree;

namespace SGT{//维护 f
	
	#define mid (L+R>>1)
	
	int idx=1;
	
	int ls[N<<2],rs[N<<2];
	bool f[N<<2];
	
	inline void pushup(int u){
		return f[u]=(f[ls[u]]&&f[rs[u]]),void();
	}
	
	inline void pushdown(int u){
		if(!f[u])return ;
		if(!ls[u])ls[u]=++idx;
		if(!rs[u])rs[u]=++idx;
		return f[ls[u]]=f[rs[u]]=1,void();
	}
	
	inline void tp(int &u,int l,int r,int L,int R){
		if(!u)u=++idx;
		if(L>r||l>R)return ;
		if(l<=L&&R<=r)return f[u]=1,void();
		pushdown(u);
		if(l<=mid)tp(ls[u],l,r,L,mid);
		if(r>mid)tp(rs[u],l,r,mid+1,R);
		return pushup(u),void();
	}
	
	inline bool chk(int u,int tar,int L,int R){
		if(!u)return 0;
		if(L==R)return f[u];
		if(L<=tar&&tar<=R)if(f[u])return 1;
		return pushdown(u),(tar<=mid?chk(ls[u],tar,L,mid):chk(rs[u],tar,mid+1,R));
	}
	
	#undef mid
	
}using namespace SGT;

inline void lsh(){//离散化时间
	sort(b+1,b+tot+1);tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=m;++i){
		qu[i].t=lower_bound(b+1,b+tot+1,qu[i].t)-b;
		if(qu[i].op==3){
			qu[i].l=lower_bound(b+1,b+tot+1,qu[i].l)-b;
			qu[i].r=lower_bound(b+1,b+tot+1,qu[i].r)-b;
		}
	}
	return ;
}

inline void work(int i){
	if(flag[qu[i].id])return ;
	int op=qu[i].op;
	if(op==3)return ;
	int l=qu[i].l,r=qu[i].r,k=qu[i].k;
	if(1==2)puts("wow");
	else if(op==1)upd(1,l,r,k,1,n);
	else if(op==2)ans.push_back(qry(1,l,r,1,n));
	return ;
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)a[i]=read();
	build(1,1,n);
	for(int i=1;i<=m;++i){
		qu[i].op=read(),b[++tot]=qu[i].t=read(),qu[i].l=read(),qu[i].r=read(),qu[i].id=i;
		if(qu[i].op==1)qu[i].k=read();
		if(qu[i].op==3)b[++tot]=qu[i].l,b[++tot]=qu[i].r;
	}
	lsh();
	for(int i=1;i<=m;++i)getmx(tott,qu[i].t);
	sort(qu+1,qu+m+1,[](opt a,opt b){return (a.t==b.t)?(a.id<b.id):(a.t<b.t);});//按题意将操作排序
	for(int i=m;i;--i){
		if(qu[i].op==3){
			if(chk(1,qu[i].t,1,tott))continue ;
			int u=1;tp(u,qu[i].l,qu[i].r,1,tott);
		}
	}
	for(int i=1;i<=m;++i)flag[qu[i].id]=chk(1,qu[i].t,1,tott);
	for(int i=1;i<=m;++i)work(i);
	printf("%d\n",ans.size());for(auto x:ans)printf("%lld\n",x);
	return 0;
}
posted @ 2025-11-12 20:23  DX3906_ourstar  阅读(7)  评论(0)    收藏  举报