【洛谷P5113】—魔女的夜宴Sabbat of the witch(分块+基数排序)

传送门

绫地宁宁天下第一!


考虑对于每一个块,用一个 s e t set set来维护每次整块的覆盖
对于每个点再维护一个 s e t set set表示对散块的覆盖
将块内每个点按照最后一次覆盖的时间排序
维护一下后缀和
对于询问,散块暴力加
整块二分找到第一个在整块覆盖后被修改的点
前面所有答案就都是整块的答案,加上后缀和即可
每次覆盖整块加进去,散块重构
每次撤销直接删去那次覆盖,散块重构

这样可以做到 O ( n n l o g n ) O(n\sqrt nlogn) O(nn logn)

考虑实际上每次加入的时间都是单调的
所以维护一个栈就可以了
对于每次重构,可以利用基数排序
由于保证赋值不超过 65000 65000 65000
可以用 b a s = 256 bas=256 bas=256基排
二分可以每次重构的时候维护一个指针指向第一个小于整块覆盖的点
由于有撤销
每次重构的时候维护一下当前时间
每次询问的时候将当前时间和上次重构比较
如果在重构之前就暴力跳指针就可以了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005,S=251,M=255;
char x;
int del[N],n,m,tot;
namespace Stk{
	int cnt,adj[N],nxt[N*(S+14)],to[N*(S+14)];
	inline void push(int u,int v){
		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
	}
	inline int front(int x){
		return to[adj[x]];
	}
	inline void pop(int x){
		while(del[to[adj[x]]])adj[x]=nxt[adj[x]];
	}
}
using Stk::pop;
using Stk::front;
using Stk::push;
int bel[N],L[N],R[N],pos[N];
struct opt{
	int l,r,v;
}q[N];
struct block{
	static cs int S=::S+10;
	int pos,siz,pt,last;
	int val[S],a[S],stk[N],top;
	ll sum[S],s;
	inline ll Sort(){
		static int buc[S],rk[S];
		ll res=0;
		for(int i=1;i<=siz;i++)val[i]=front(i+pos),res+=(val[i]?0:a[i]);
		for(int i=0;i<=M;i++)buc[i]=0;
		for(int i=1;i<=siz;i++)buc[val[i]&M]++;
		for(int i=1;i<=M;i++)buc[i]+=buc[i-1];
		for(int i=siz;i;i--)rk[buc[val[i]&M]--]=val[i];
		for(int i=0;i<=M;i++)buc[i]=0;
		for(int i=1;i<=siz;i++)buc[val[i]>>8]++;
		for(int i=1;i<=M;i++)buc[i]+=buc[i-1];
		for(int i=siz;i;i--)val[buc[rk[i]>>8]--]=rk[i];
		return res;
	}
	inline void build(){
		s=0;
		for(int i=1;i<=siz;i++)s+=a[i];
		sum[0]=s;
	}
	inline void rebuild(){
		ll res=Sort();last=stk[top];
		for(int i=siz-1;~i;i--)sum[i]=sum[i+1]+q[val[i+1]].v;sum[0]+=res;
		pt=0;
		while(pt<siz&&val[pt+1]<last)pt++;
		s=sum[pt]+1ll*pt*q[last].v;
	}
	inline void insert(int x){
		stk[++top]=x,s=1ll*q[x].v*siz;
	}
	inline void reset(){
		while(del[stk[top]])top--;
		if(stk[top]<=last){
			while(pt&&val[pt]>=stk[top])pt--;
			s=sum[pt]+1ll*pt*q[stk[top]].v;
		}
		else s=1ll*q[stk[top]].v*siz;
	}
	inline ll query(int l,int r){
		ll res=0;
		int t=stk[top];
		if(t)for(int i=l;i<=r;i++)res+=(front(i)<t)?q[t].v:q[front(i)].v;
		else for(int i=l;i<=r;i++)res+=(front(i)?q[front(i)].v:a[i-pos]);
		return res;
	}
}A[N/S+5];
char y;
inline void update(int l,int r,int v){
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++)push(i,v);
		A[bel[l]].rebuild();return;
	}
	for(int i=l;i<=R[bel[l]];i++)push(i,v);
	A[bel[l]].rebuild();
	for(int i=L[bel[r]];i<=r;i++)push(i,v);
	A[bel[r]].rebuild();
	for(int i=bel[l]+1;i<bel[r];i++)A[i].insert(v);
}
inline void delet(int l,int r){
	if(bel[l]==bel[r]){
		for(int i=l;i<=r;i++)pop(i);
		A[bel[l]].rebuild();return;
	}
	for(int i=l;i<=R[bel[l]];i++)pop(i);
	A[bel[l]].rebuild();
	for(int i=L[bel[r]];i<=r;i++)pop(i);
	A[bel[r]].rebuild();
	for(int i=bel[l]+1;i<bel[r];i++)A[i].reset();
}
inline ll query(int l,int r){
	if(bel[l]==bel[r])return A[bel[l]].query(l,r);
	ll res=0;
	res+=A[bel[l]].query(l,R[bel[l]]);
	res+=A[bel[r]].query(L[bel[r]],r);
	for(int i=bel[l]+1;i<bel[r];i++)res+=A[i].s;
	return res;
}
ll last;
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)bel[i]=(i-1)/S+1;
	for(int i=1;i<=n;i++)A[bel[i]].a[(i-1)%S+1]=read();
	for(int i=1;i<=bel[n];i++)L[i]=(i-1)*S+1,R[i]=i*S;
	R[bel[n]]=n;
	for(int i=1;i<=bel[n];i++)A[i].pos=L[i]-1;
	for(int i=1;i<=n;i++)A[bel[i]].siz=i-L[bel[i]]+1;
	for(int i=1;i<=bel[n];i++)A[i].build();
	while(m--){
		int op=read();
		if(op==1){
			int l=read()^last,r=read()^last,v=read();
			q[++tot]=opt{l,r,v};
			update(l,r,tot);
		}
		else if(op==2){
			int l=read()^last,r=read()^last;
			cout<<(last=query(l,r))<<'\n';
		}
		else{
			int x=read()^last;
			del[x]=1;
			delet(q[x].l,q[x].r);
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值