专栏文章

题解:P12448

P12448题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min71lbx
此快照首次捕获于
2025/12/01 21:37
3 个月前
此快照最后确认于
2025/12/01 21:37
3 个月前
查看原文
首先可以想到一个静态的做法。按照原式计算是困难的,不妨变换顺序,计算每个点对答案的贡献,需要处理出 L[i],R[i]L[i], R[i] 表示 ii 点最大值能延申到的区间。推一下式子,贡献可表示为 33 段加等差数列的形式,可用线段树简单维护(注意标记的首项下传细节!)。
观察修改的样子,发现修改前后只是在某些区间的答案上简单加 11,故考虑求这些区间的个数。容易发现这只跟左边、右边第一个大于等于 a[x]a[x] 的位置有关,与静态相似地做。
CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
int rd(){
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	int ret = 0;
	while('0' <= c && c <= '9') ret = (ret << 3) + (ret << 1) + c - '0', c = getchar();
	return ret;
}

int n, m, ID;
long long a[500002];

struct Segment_Tree{
	#define l(pos) pos << 1
	#define r(pos) (pos << 1) | 1
	struct Node {
		int num;
		int tagl, tags;
		bool havetag;
	}t[4000002];
	void pushdown(int pos,int l,int r){
		int mid = (l + r) >> 1;
		if(t[pos].havetag){
			t[pos].num += (2*t[pos].tagl + (r-l)*t[pos].tags) * (r-l+1) / 2;
			t[l(pos)].havetag = 1, t[l(pos)].tagl += t[pos].tagl, t[l(pos)].tags += t[pos].tags;
			t[r(pos)].havetag = 1, t[r(pos)].tagl += t[pos].tagl + (mid+1-l)*t[pos].tags, t[r(pos)].tags += t[pos].tags;
			t[pos].tagl = 0, t[pos].tags = 0, t[pos].havetag = 0;
		}
	}
	void Add(int pos,int l,int r,int tarl,int tarr,int x,int y){
		if(tarl > tarr) return;
		pushdown(pos, l, r);
		if(tarl <= l && r <= tarr){
			t[pos].havetag = 1;
			t[pos].tagl = x, t[pos].tags = y;
			pushdown(pos, l, r);
			return;
		}
		int mid = (l + r) >> 1;
		if(tarl <= mid) Add(l(pos), l, mid, tarl, tarr, x, y);
		if(mid+1 <= tarr) {
			if(tarl <= mid+1) Add(r(pos), mid+1, r, mid+1, tarr, x+(mid+1-tarl)*y, y);
			else Add(r(pos), mid+1, r, tarl, tarr, x, y);
		}
		pushdown(l(pos), l, mid), pushdown(r(pos), mid+1, r);
		t[pos].num = t[l(pos)].num + t[r(pos)].num;
	}
	int Query(int pos,int l,int r,int tarl,int tarr){
		pushdown(pos, l, r);
		if(tarl <= l && r <= tarr) return t[pos].num;
		int mid = (l + r) >> 1, ret = 0;
		if(tarl <= mid) ret += Query(l(pos), l, mid, tarl, tarr);
		if(mid+1 <= tarr) ret += Query(r(pos), mid+1, r, tarl, tarr);
		return ret;
	}
};
Segment_Tree T;
struct Line_Tree{
	#define l(pos) pos << 1
	#define r(pos) (pos << 1) | 1
	int Max[4000002];
	void Add(int pos,int l,int r,int tar,int s){
		if(l == r) {
			Max[pos] += s;
			return;
		}
		int mid = (l + r) >> 1;
		if(tar <= mid) Add(l(pos), l, mid, tar, s);
		else Add(r(pos), mid+1, r, tar, s);
		Max[pos] = max(Max[l(pos)], Max[r(pos)]);
	}
	int Finderl(int pos,int l,int r,int tar,int tars){
		if(l == r){
			if(Max[pos] < tars) return -1;
			return l;
		}
		int mid = (l + r) >> 1;
		if(tar <= mid) return Finderl(l(pos), l, mid, tar, tars);
		if(mid < tar && tar < r){
			int R = Finderl(r(pos), mid+1, r, tar, tars);
			if(R != -1) return R;
			return Finderl(l(pos), l, mid, tar, tars);
		}
		if(Max[r(pos)] >= tars) return Finderl(r(pos), mid+1, r, tar, tars);
		return Finderl(l(pos), l, mid, tar, tars);
	}
	int Finderr(int pos,int l,int r,int tar,int tars){
		if(l == r){
			if(Max[pos] < tars) return -1;
			return l;
		}
		int mid = (l + r) >> 1;
		if(tar >= mid+1) return Finderr(r(pos), mid+1, r, tar, tars);
		if(l < tar && tar < mid+1){
			int R = Finderr(l(pos), l, mid, tar, tars);
			if(R != -1) return R;
			return Finderr(r(pos), mid+1, r, tar, tars);
		}
		if(Max[l(pos)] >= tars) return Finderr(l(pos), l, mid, tar, tars);
		return Finderr(r(pos), mid+1, r, tar, tars);
	}
};
Line_Tree L;

signed main(){
	//freopen("data.in","r",stdin);
	//freopen("my.out","w",stdout);
	
	n = rd(), m = rd(), ID = rd();
	L.Add(1, -1, n+2, 0, 1e18);
	L.Add(1, -1, n+2, n+1, 1e18);
	L.Add(1, -1, n+2, -1, 1e18);
	L.Add(1, -1, n+2, n+2, 1e18);
	for(int i=1;i<=n;i++) {
		a[i] = rd();
		L.Add(1, -1, n+2, i, a[i]);
	}
	
	for(int i=1;i<=n;i++){
		int l = L.Finderl(1, -1, n+2, i-1, a[i]+1) + 1, r = L.Finderr(1, -1, n+2, i+1, a[i]) - 1;
		
		int s = min(r - i + 1, i - l + 1);
		T.Add(1, 1, n, 1, s-1, a[i], a[i]);
		T.Add(1, 1, n, s, r-l+1-s, s*a[i], 0);
		T.Add(1, 1, n, r-l+2-s, r-l+1, s*a[i], -a[i]);
	}
	
	for(int i=1;i<=m;i++){
		int opt;
		int x;
		opt = rd(), x = rd();
		if(opt == 1){
			printf("%lld\n",T.Query(1, 1, n, x, x));
		}
		else {
			a[x]++;
			int l = L.Finderl(1, -1, n+2, x-1, a[x]) + 1, r = L.Finderr(1, -1, n+2, x+1, a[x]) - 1;
			//cout << l << ' ' << r << endl;
			
			int MIN = min(x-l+1, r-x+1), MAX = max(x-l+1, r-x+1);
			T.Add(1, 1, n, 1, MIN-1, 1, 1);
			T.Add(1, 1, n, MIN, MAX - 1, MIN, 0);
			T.Add(1, 1, n, MAX, r-l+1, MIN, -1);
			
			L.Add(1, -1, n+2, x, 1);
		}
	}
	
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...