*题解:P3863 序列

题目链接

解析

将序列视作一维,时间视作一维,那么查询和修改可以看作是在二维平面上的操作。具体地,如果令横轴为序列维,从左至右下标逐渐增加,纵轴为时间维,从下至上时刻逐渐变大。那么对于一次发生在第 \(i\) 秒的修改 \((l,r,x)\),其相当于对左上角为 \((l,q)\),右下角为 \((r,i)\) 的矩形区域加上 \(x\)\(q\) 为题目中的询问组数,也是最大时刻。对于一次发生在第 \(i\) 秒的查询 \((p,y)\),其相当于统计第 \((p,0)\)\((p,i - 1)\) 中大于等于 \(y\) 的点的个数。

考虑扫描线,扫序列维,用数据结构维护时间维。对于修改,我们使用差分,将每个修改拆成在位置 \(l\)\(x\) 和在位置 \(r + 1\)\(x\);对于查询,要求大于等于 \(y\) 的点的个数,我们使用分块,每个块内维护原始序列和排序后序列,查询时对整块进行二分,散块暴力即可。

时间复杂度 \(O(nB\log B)\)\(B\) 为块长。

代码

#include <bits/stdc++.h>
#define ls(x) (((x) << 1))
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
const int N = 3e5 + 5,B = 300;
struct Q{
	int op,t,p,x;
	friend bool operator < (Q a,Q b){
		return a.p != b.p ? a.p < b.p : a.op < b.op;
	}
};
int a[N];
int n,q;
ll tag[N / B + 5],num[N],ori[N],srt[N],l[N / B + 5],r[N / B + 5];
void build(int n){
	int cnt = 0;
	for(int i=1;(i - 1) * B <= q;i++){
		cnt++;
		l[i] = (i - 1) * B;
		r[i] = min(i * B - 1,q);
	}
	for(int i=1;i<=cnt;i++){
		for(int j=l[i];j<=r[i];j++){
			num[j] = i;
		}
	}
}
void add(int p,int x){
	if(num[p] == num[q]){
		for(int i=p;i<=q;i++){
			ori[i] += x;
		}
		for(int i=l[num[p]];i<=r[num[p]];i++){
			ori[i] += tag[num[p]]; 
			srt[i] = ori[i];
		}
		tag[num[p]] = 0;
		sort(srt + l[num[p]],srt + r[num[p]] + 1);
		return;
	}
	for(int i=num[p] + 1;i<=num[q] - 1;i++){
		tag[i] += x;
	}
	for(int i=l[num[p]];i<=r[num[p]];i++){
		ori[i] += tag[num[p]];
		if(i >= p) ori[i] += x;
		srt[i] = ori[i];
	}
	sort(srt + l[num[p]],srt + r[num[p]] + 1);
	tag[num[p]] = 0;
	for(int i=l[num[q]];i<=r[num[q]];i++){
		if(i >= p) ori[i] += x;
		ori[i] += tag[num[q]];
		srt[i] = ori[i];
	}
	sort(srt + l[num[q]],srt + r[num[q]] + 1);
	tag[num[q]] = 0;	
}
int ask(int p,int x){
	int res = 0;
	if(num[p] == num[0]){
		for(int i=0;i<=p;i++){
			res += (ori[i] + tag[num[p]]) >= x;
		}
		return res;
	}
	
	for(int i=num[0] + 1;i<=num[p] - 1;i++){
		int t = lower_bound(srt + l[i],srt + r[i] + 1,x - tag[i]) - srt;	
		res += r[i] - t + 1;
	}
	for(int i=0;i<=r[num[0]];i++){
		res += (ori[i] + tag[num[0]]) >= x;
	}
	for(int i=l[num[p]];i<=p;i++){
		res += (ori[i] + tag[num[p]]) >= x;
	}
	return res;
}
vector<Q> qry;
int res[N];
int read(){
	int a = 1,x = 0;
	char ch = getchar();
	while(ch > '9' || ch < '0'){
		if(ch == '-') a = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return a * x;
}
signed main(){
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	n = read(),q = read();
	build(q);
	for(int i=1;i<=n;i++){
		a[i] = read();
		qry.push_back({1,0,i,a[i]});
		qry.push_back({1,0,i + 1,-a[i]});
	}
	for(int i=1;i<=q;i++){
		int op;
		op = read();
		if(op == 1){
			int l,r,x;

			l = read(),r = read(),x = read();
			qry.push_back({1,i,l,x});
			qry.push_back({1,i,r + 1,-x});
		}else{
			int p,y;
			p = read();
			y = read();
			qry.push_back({2,i,p,y});
		}
	} 
	memset(res,-1,sizeof(res));
	sort(qry.begin(),qry.end());
	int now = 0;
	for(int i=1;i<=n;i++){
		while(now < qry.size() && qry[now].p == i){
			if(qry[now].op == 1){
				add(qry[now].t,qry[now].x);		
			}else{
				res[qry[now].t] = ask(qry[now].t - 1,qry[now].x);
			}
			now++;
		}
	}
	for(int i=1;i<=q;i++){
		if(res[i] != -1){
			cout<<res[i]<<'\n';
		}
	}
	return 0;
}


posted @ 2026-06-18 21:05  yutar  阅读(4)  评论(0)    收藏  举报