8.22 T4 (吉司机线段树)伤痕累累的心,在暴雨中仍然放声歌唱

http://cplusoj.com/d/senior/p/SS240709D

假设现在只有 [ 1 , x ] [1,x] [1,x]

考虑一个数的贡献区间为 r − l − 1 r-l-1 rl1 l , r l,r l,r 为左右第一个比它大的数的坐标

此时的答案是 ∑ r − ∑ l − x \sum r-\sum l-x rlx。我们不妨先算 ∑ r \sum r r,再reverse一下

要维护每个东西右边第一个比它大的东西,而且要维护还是相对坐标,考虑这个东西加入会有什么影响?

  1. 它自己是 x + 1 x + 1 x+1
  2. 它右边全部 + 1 +1 +1
  3. 它左边全部对 x x x 取min

上面三个东西直接拿吉司机维护即可

#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
 #define debag(...) fprintf(stderr, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
 #define debag(...) void(0)
#endif
#define int long long
inline int read(){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;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
//#define mo
#define N 200010
int n, m, i, j, k, T;

namespace Sol {
#define mid ((l + r) >> 1)
#define ls (k << 1)
#define rs (k << 1 | 1)
	int mp[N]; 
	struct Segment_tree {
		int len[N << 2], slen[N << 2], sm[N << 2], d1[N << 2], d2[N << 2]; 
		int mx1[N << 2], mx2[N << 2]; 
		void push_down(int k) {
			int l = ls, r = rs; 
			if(mx1[l] == mx1[r]) {
				mx1[l] += d1[k]; mx1[r] += d1[k]; 
				mx2[l] += d2[k]; mx2[r] += d2[k]; 
				sm[l] += d1[k] * len[l]; sm[r] += d1[k] * len[r]; 
				sm[l] += d2[k] * slen[l]; sm[r] += d2[k] * slen[r]; 
				d1[l] += d1[k]; d1[r] += d1[k]; 
				d2[l] += d2[k]; d2[r] += d2[k]; 
			}
			else {
				if(mx1[l] < mx1[r]) swap(l, r); 
				mx1[l] += d1[k]; 
				mx1[r] += d2[k];  mx2[l] += d2[k]; mx2[r] += d2[k]; 
				sm[l] += d1[k] * len[l]; sm[l] += d2[k] * slen[l]; 
				sm[r] += d2[k] * (len[r] + slen[r]); 
				d1[l] += d1[k]; 
				d1[r] += d2[k]; d2[l] += d2[k]; d2[r] += d2[k]; 
			}
			d1[k] = d2[k] = 0; 
		}
		void push_up(int k) {
			sm[k] = sm[ls] + sm[rs]; 
			if(mx1[ls] == mx1[rs]) {
				mx1[k] = mx1[ls]; 
				mx2[k] = max(mx2[ls], mx2[rs]); 
				len[k] = len[ls] + len[rs]; 
				slen[k] = slen[ls] + slen[rs]; 
			}
			if(mx1[ls] > mx1[rs]) {
				mx1[k] = mx1[ls]; 
				mx2[k] = max(mx2[ls], mx1[rs]); 
				len[k] = len[ls]; 
				slen[k] = slen[ls] + slen[rs] + len[rs]; 
			}
			if(mx1[ls] < mx1[rs]) {
				mx1[k] = mx1[rs]; 
				mx2[k] = max(mx1[ls], mx2[rs]); 
				len[k] = len[rs]; 
				slen[k] = slen[ls] + slen[rs] + len[ls]; 
			}
		}
		void build(int k, int l, int r) {
			mx1[k] = mx2[k] = len[k] = slen[k] = d1[k] = d2[k] = sm[k] = 0; 
			if(l == r) return ; 
			build(ls, l, mid); build(rs, mid + 1, r); 
		}
		void modify(int k, int l, int r, int x, int y) {
			if(l == r) {
				mx1[k] = sm[k] = y; len[k] = 1; 
				mx2[k] = slen[k] = d1[k] = d2[k] = 0; 
				return ; 
			}
			push_down(k); 
			if(x <= mid) modify(ls, l, mid, x, y); 
			else modify(rs, mid + 1, r, x, y); 
			push_up(k); 
		}
		void add(int k, int l, int r, int x, int y) {
			if(l >= x && r <= y) {
				mx1[k]++; mx2[k]++; d1[k]++; d2[k]++; sm[k] += (len[k] + slen[k]); 
				return ; 
			}
			push_down(k); 
			if(x <= mid) add(ls, l, mid, x, y); 
			if(y >= mid + 1) add(rs, mid + 1, r, x, y); 
			push_up(k); 
		}
		void qmin(int k, int l, int r, int x, int y, int p) {
			if(l >= x && r <= y) {
				debug("[%lld %lld] for %lld // %lld %lld\n", l, r, p, mx1[k], mx2[k]); 
				if(p >= mx1[k]) return ; 
				if(p <= mx2[k]) {
					push_down(k); 
					qmin(ls, l, mid, x, y, p); 
					qmin(rs, mid + 1, r, x, y, p); 
					push_up(k); 
					return ; 
				}
				debug("At [%lld %lld] (%lld) {%lld %lld %lld}\n", l, r, len[k], d1[k], sm[k], mx1[k]); 
				d1[k] -= mx1[k] - p; 
				sm[k] -= (mx1[k] - p) * len[k]; 
				mx1[k] = p; 
				debug("{%lld %lld %lld}\n", d1[k], sm[k], mx1[k]); 
				return ; 
			}
			push_down(k); 
			if(x <= mid) qmin(ls, l, mid, x, y, p); 
			if(y >= mid + 1) qmin(rs, mid + 1, r, x, y, p); 
			push_up(k); 
		}
	}Seg;
	struct Binay_tree {
		int cnt[N]; 
		void clear() { memset(cnt, 0, sizeof(cnt)); 
		}
		void add(int x) {
			while(x < N) cnt[x]++, x += x & -x; 
		}
		int qry(int x) {
			int ans = 0; 
			while(x) ans += cnt[x], x -= x & -x; 
			return ans; 
		}
	}Bin;
	void main(int *a, int *A) {
		Seg.build(1, 1, n); Bin.clear(); 
		for(i = 1; i <= n; ++i) mp[a[i]] = i; 
		for(i = 1; i <= n; ++i) {
			int p = mp[i]; Bin.add(p); k = Bin.qry(p); 
//			if(i == 4) {
//				if(p != n) Seg.add(1, 1, n, p + 1, n); 
//				Seg.modify(1, 1, n, p, i + 1); 
//				if(p != 1) Seg.qmin(1, 1, n, 1, p - 1, k); 
//
//			}
//			else {
				if(p != n) Seg.add(1, 1, n, p + 1, n); 
				Seg.modify(1, 1, n, p, i + 1); 
				if(p != 1) Seg.qmin(1, 1, n, 1, p - 1, k); 
				
//			}
			A[i] = Seg.sm[1]; 		
//			printf(">>> %lld : %lld\n", i, A[i]); 
		}
	}
}

int a[N], A[N], B[N]; 

signed main()
{
	freopen("scar.in", "r", stdin);
	freopen("scar.out", "w", stdout);
//	srand(time(NULL));
//	T=read();
//	while(T--) {
//
//	}
	n = read(); 
	for(i = 1; i <= n; ++i) a[i] = read(); 
	Sol :: main(a, A); 
//	for(i = 1; i <= n; ++i) debug("%lld ", A[i]); debug("\n"); 
	reverse(a + 1, a + n + 1); 
	Sol :: main(a, B); 
	for(i = 1; i <= n; ++i) printf("%lld\n", A[i] + B[i] - i * (i + 2)); 
	return 0;
}



  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: iar8.22.1是瑞典IAR系统公司开发的一款嵌入式软件开发工具,用于编译、调试嵌入式系统的代码。在使用过程,为了方便用户的使用,IAR公司发布了文版本的补丁,让用户可以使用更加熟悉的文界面进行开发。 通过安装iar8.22.1文补丁,用户可以将软件界面的显示语言变更为文,包括菜单、对话框、工具栏等部分。这样做可以让用户更加直观地理解软件的功能,减少因语言不通而产生的误解和困惑。 此外,文补丁还可以提高用户的工作效率。在使用文界面时,用户不需要再费理解英文界面,可以更加专注于代码的编写。同时,文界面可以让用户更快地找到需要的功能,提高使用的便捷性和效率。 总的来说,IAR8.22.1文补丁是一个非常有用的小工具。它不仅方便了用户的使用,还提高了用户的工作效率。对于需要使用IAR软件进行嵌入式系统开发的用户来说,安装此文补丁是一项非常值得推荐的操作。 ### 回答2: IAR 8.22.1是一款常用的集成开发环境(IDE)软件,可用于开发嵌入式系统和微控制器应用。该软件最初是国外开发的,因此界面和文本都是英语的,不方便国用户使用。因此,出现了IAR 8.22.1文补丁,可以将IAR 8.22.1软件翻译成文。 IAR 8.22.1文补丁的作用是将IAR 8.22.1软件的英文界面和文本翻译成文,让用户更加方便地使用该软件,提高工作效率。此外,文补丁还可以改善软件的交互体验,使用户更容易理解各项功能和选项的作用。 IAR 8.22.1文补丁使用方法简单,只需下载并解压缩补丁文件,然后将其文翻译文件覆盖到软件安装目录的相应文件,即可完成安装。在安装完成后,用户可以在IAR 8.22.1软件的设置选择文语言,就可以看到软件已经被翻译成文了。 总之,IAR 8.22.1文补丁为用户提供了一种简单、方便的方式,可以快速将IAR 8.22.1软件转化成文界面和文本,提高工作效率,增强用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值