首页 > 其他分享 >P3863 序列(分块)

P3863 序列(分块)

时间:2024-09-11 20:51:18浏览次数:1  
标签:bel 分块 int rep maxn 序列 P3863 include define

感觉是一个比较厉害的 trick,并且从来没见过,记录一下。

题意

给定 \(n\) 个数和 \(q\) 次操作:

  • 1 l r x:区间 \([l,r]\) 加 \(x\)。
  • 2 x v:查询在询问之前有多少时刻 \(a_x\ge v\)。一次操作定义为一个时刻,初始为 \(0\) 时刻。

\(n,q\le 10^5\)

分析

如果 \(x\ge 0\),那么 \(a_i\) 的值不降,直接二分+主席树维护即可。只是提一嘴我的原始思路,跟这题正解没关系。

但是 \(x<0\),上面的做法就假透了。考虑一个新做法。

假设对 \(a_i\) 的询问,我们找出了它在所有时间轴上的值 \(b_i\),原题的询问等价于询问时间轴在 \([0,t)\) 中 \(b_i\ge v\) 的 \(i\) 个数。这是分块的经典例题。如果我们只维护一个 \(a_i\),那么我们直接将值域分块,然后整块二分散块暴力即可。

但是我们要维护 \(n\) 个数的区间加。

区间加这个东西会给区间内的所有数加同一个偏移量废话,我们或许可以考虑从 \(i-1\) 继承过来 \(i\) 的所有版本的值。这样的话,我们只需要将 \([l,r]\) 拆成 \(l,r+1\) 两个单点,在 \(l\) 处增加贡献,在 \(r+1\) 处去除贡献。对于一个单点加,就相当于对 \([t,q]\) 的时间段里 \(a_i\) 的历史值做区间加。查询直接套用上文的解法。

时间复杂度 \(O(n\sqrt n\log n)\)。

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0);
#define OTIE cout.tie(0);
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define all(x) x.begin(),x.end()
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) (x&-x)
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mem(x,y) memset(x,y,sizeof x)
//#define double long double
#define int long long
//#define int __int128
using namespace std;
typedef long long i64;
typedef unsigned long long u64;
using pii=pair<int,int>;
bool greating(int x,int y){return x>y;}
bool greatingll(long long x,long long y){return x>y;}
inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}return x*f;
}
inline void write(int x,char ch='\0'){
	if(x<0){x=-x;putchar('-');}
	int y=0;char z[40];
	while(x||!y){z[y++]=x%10+48;x/=10;}
	while(y--)putchar(z[y]);if(ch!='\0')putchar(ch);
}
bool Mbg;
const int maxn=1e5+5,maxm=4e5+5,inf=0x3f3f3f3f,B=320;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,Q,a[maxn];
vector<pii>mdf[maxn];
using piii=pair<pair<int,int>,int>;
vector<piii>ask[maxn];
int ans[maxn];
//b sorted c unsorted
int b[maxn],c[maxn],tag[maxn];
int L[maxn],R[maxn],bel[maxn],num;
void remake(int x){
	rep(i,L[x],R[x])c[i]+=tag[x],b[i]=c[i];
	tag[x]=0;
	sort(b+L[x],b+R[x]+1);
}
void upd(int l,int r,int x){
	if(bel[l]==bel[r]){
		rep(i,l,r)c[i]+=x;
		remake(bel[l]);
		return;
	}
	rep(i,l,R[bel[l]])c[i]+=x;remake(bel[l]);
	rep(i,bel[l]+1,bel[r]-1)tag[i]+=x;
	rep(i,L[bel[r]],r)c[i]+=x;remake(bel[r]);
}
int qry(int l,int r,int val){
	int res=0;
	if(bel[l]==bel[r]){
		rep(i,l,r)if(c[i]+tag[bel[l]]>=val)++res;
		return res;
	}
	rep(i,l,R[bel[l]])if(c[i]+tag[bel[l]]>=val)++res;
	rep(i,bel[l]+1,bel[r]-1){
		int ps=lower_bound(b+L[i],b+R[i]+1,val-tag[i])-b;
		res+=R[i]-ps+1;
	}
	rep(i,L[bel[r]],r)if(c[i]+tag[bel[r]]>=val)++res;
	return res;
}
inline void solve_the_problem(){
	n=rd(),Q=rd(),num=Q/B+1;
	rep(i,1,num){
		L[i]=(i-1)*B,R[i]=min(i*B-1,Q);
		rep(j,L[i],R[i])bel[j]=i;
	}
	rep(i,1,n)a[i]=rd();
	int qrycnt=0;
	rep(i,1,Q){
		int op=rd(),l=rd(),r=rd(),x;
		if(op==1){
			x=rd();
			mdf[l].emplace_back(mp(x,i)),mdf[r+1].emplace_back(mp(-x,i));
		}else{
			ask[l].emplace_back(mp(mp(r,i-1),++qrycnt));
		}
	}
	rep(i,1,n){
		for(pii j:mdf[i]){
			int val=j.fi,t=j.se;
			upd(t,Q-1,val);
		}
		for(piii j:ask[i]){
			int val=j.fi.fi,t=j.fi.se,id=j.se;
			ans[id]=qry(0,t,val-a[i]);
		}
	}
	rep(i,1,qrycnt)write(ans[i],10);
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
//	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;
	while(_--)solve_the_problem();
}
/*

*/

标签:bel,分块,int,rep,maxn,序列,P3863,include,define
From: https://www.cnblogs.com/dcytrl/p/18408976

相关文章

  • P1439 【模板】最长公共子序列
    link【模板】最长公共子序列题目描述给出$1,2,\ldots,n$的两个排列$P_1$和$P_2$,求它们的最长公共子序列。输入格式第一行是一个数$n$。接下来两行,每行为$n$个数,为自然数$1,2,\ldots,n$的一个排列。输出格式一个数,即最长公共子序列的长度。样例#1样例输入#1......
  • 代码随想录训练营day44|1143.最长公共子序列,1035.不相交的线, 53. 最大子序和,392.判
    1143.最长公共子序列这题并不要求连续子序列的要求是可以删除某些元素,但不能改变顺序。顺着上题的思路,这题也应该设立一个二维数组vector<vector<int>>dp(text1.size(),vector<int>(text2.size(),0));dp[i][j]表示的是以text1[i]为结尾的字符串和以text2[j]为结尾的......
  • Springboot枚举自定义序列化
    packagexxxxxxxxxxxxx;importcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.databind.JsonSerializer;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.SerializerProvider;importcom.fasterx......
  • 【高级编程】Java IO流(补)序列化 & 反序列化
    序列化(ObjectOutputStream)&反序列化(ObjectInputStream)Java的序列化和反序列化是用于将对象转换为字节流的过程,以便在网络上传输或保存到磁盘,然后将这些字节流再转换回对象。这个过程是Java中处理对象持久化和传输的常见方法。序列化是将对象的状态转换为字节流的过......
  • LeetCode: 673.最长子序列的数量 动态规划 时间复杂度O(n*n)
    673.最长子序列的数量LeetCode原题连接673.最长子序列的数量题目描述给定一个未排序的整数数组,找到最长递增子序列的个数。示例1:输入:[1,3,5,4,7]输出:2解释:有两个最长递增子序列,分别是[1,3,4,7]和[1,3,5,7]。示例2:输入:[2,2,2,2,2]输出:5......
  • P3730 曼哈顿交易(经典题,莫队+值域分块)
    记录这一类很典的题目。题意给定\(n\)个数,\(q\)次询问区间\([l,r]\)内出现次数第\(k\)小的数的出现次数。若区间内不同数的个数小于\(k\)输出-1。\(n,q\le10^5\)。分析发现正常的数据结构以及分块都很难维护这种信息,考虑莫队。莫队加入数时,我们需要更新一个数的......
  • 115. 不同的子序列(leetcode)
    https://leetcode.cn/problems/distinct-subsequences/submissions/563375885/这题比较有难度,具体不太好想到,需要以是否选择s[i]来划分子集这位描述的很清楚,不做过多赘述classSolution{publicintnumDistinct(Strings,Stringt){//f[i][j]表示s中前i个......
  • RapidJSON 的坑--允许Object对象存在相同的key,且key为数字时序列化报异常
    RapidJSON的坑--允许Object对象存在相同的key,且key为数字时序列化报异常测试代码如下:1voidshow(rapidjson::Document&doc)2{3printf("-----------------foriterator\nMemberCount:%d\n",doc.MemberCount());4for(autoit=doc.MemberBegin();it!=doc......
  • 6、Python如何统计序列中元素的频度
    有一个列表如下:data=['a','c','f','b','f','e','k','d','f','k']如何统计每个元素出现的次数呢?方案一:使用Listcount方法如果只要知道某一个元素出现的次数,直接使用Listcount方法就可以data=['......
  • 类实现序列化接口后自动生成序列化ID
    1、为什么要实现序列化接口?在Java中,Serializable是一个标记接口(markerinterface),它本身并不包含任何方法。当一个类实现了Serializable接口,意味着这个类的对象可以被序列化,即可以转换为字节流,从而可以通过网络传输或者保存到磁盘上。为了保证序列化对象的唯一性以及版本控......