abc407 赛后复盘

从 F 开题,发现写完只剩 15min,遗憾离场,但我报的 unr(

首先我们拆贡献:

对于一个区间 \([l,r]\)\(x\) 为其中的最大值,下标为 \(i\)
显然,\(x\) 可以对最多长度为 \(k=r-l+1\) 的串产生贡献,分别在长度为 \(k\) 的串中的任意一个位置,那么 \(x\) 产生的贡献会像这样:

长度 贡献
\(1\) \(x\)
\(2\) \(2x\)
\(3\) \(3x\)
\(\cdots\) \(\cdots\)
\(k-2\) \(3x\)
\(k-1\) \(2x\)
\(k\) \(x\)

但是上表中我们忽略了一个细节,就是 \(x\) 可能不能遍历每一个位置,像这样,当 \(k=5,i=2\) 时:1 2 1 1 1;或者这样,当 \(k=5,i=4\) 时:1 1 1 2 1\(x\) 只能遍历 \(\min(r-i,i-l)\) 个格子。我们不妨设他为 \(sm\)
那么这个贡献函数的图像将会长得像下面这样:

函数关于中间虚线对称轴对称,横轴为长度,纵轴为贡献。
那么我们就只用处理两边的区间加等差数列单点求和了,不会的看看这个P1438 无聊的数列但是因为只有最后有查询,所以用差分数组就好了。

代码写的丑,轻喷:

#include<bits/stdc++.h>

#define int ll
#define pii pair<int,int> 
#define pll pair<long long,long long> 
#define ll long long
#define i128 __int128

#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first 
#define scd second 
#define dbg puts("IAKIOI")

using namespace std;

int read() {
	int x=0,f=1; char c=getchar();
	for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); 
	for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }

const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }

#define maxn 200050

int n,a[maxn];
int stk1[maxn],stk2[maxn];
int L[maxn],R[maxn];
int top1,top2;

struct node {
	int sum,tag;
	int l,r;
}tr[maxn<<2];

void pu(int idx) {
	tr[idx].sum=tr[lc(idx)].sum+tr[rc(idx)].sum;
}

void pd(int idx) {
	if(!tr[idx].tag) return ;
	tr[lc(idx)].tag+=tr[idx].tag;
	tr[rc(idx)].tag+=tr[idx].tag;
	tr[lc(idx)].sum+=tr[idx].tag*(tr[lc(idx)].r-tr[lc(idx)].l+1);
	tr[rc(idx)].sum+=tr[idx].tag*(tr[rc(idx)].r-tr[rc(idx)].l+1);
	tr[idx].tag=0;
}

void build(int idx,int l,int r,int a[]) {
	tr[idx].l=l,tr[idx].r=r;
	if(l==r) {
		tr[idx].sum=a[l];
		return ;
	}
	int mid=l+r>>1;
	build(lc(idx),l,mid,a);
	build(rc(idx),mid+1,r,a);
	pu(idx);
}

void add(int idx,int l,int r,int L,int R,int val ){
	if(L<=l&&r<=R) {
		tr[idx].sum+=val*(r-l+1);
		tr[idx].tag+=val;
		return ;
	}
	pd(idx);
	int mid=l+r>>1;
	if(L<=mid) add(lc(idx),l,mid,L,R,val);
	if(R>mid) add(rc(idx),mid+1,r,L,R,val);
	pu(idx);
}

int query(int idx,int l,int r,int L,int R) {
	if(L<=l&&r<=R) return tr[idx].sum;
	pd(idx);
	int mid=l+r>>1,res=0;
	if(L<=mid) res+=query(lc(idx),l,mid,L,R);
	if(R>mid) res+=query(rc(idx),mid+1,r,L,R);
	return res;
}


void work() {
	in1(n);
	build(1,1,maxn-1,a);
	For(i,1,n) in1(a[i]);
	a[0]=a[n+1]=1e9;
	stk1[++top1]=0;
	For(i,1,n) {
		while(top1>0&&a[stk1[top1]]<a[i]) top1--;
		L[i]=stk1[top1];
		stk1[++top1]=i;
	}
	stk2[++top2]=n+1;
	Rep(i,n,1) {
		while(top2>0&&a[stk2[top2]]<=a[i]) top2--;
		R[i]=stk2[top2];
		stk2[++top2]=i;
	}
	For(i,1,n) {
		int sm=min(i-L[i],R[i]-i);
		int l=0,r=0,k=0,d=0;
		if(sm!=1) {
			l=1,r=sm-1,k=a[i],d=a[i];
			if(l+1<=r) add(1,1,maxn-1,l+1,r,d);
			add(1,1,maxn-1,l,l,k);
			add(1,1,maxn-1,r+1,r+1,-k-d*(r-l));
		}
//		cout<<"idx:"<<i<<':';
//		cout<<sm<<' '<<l<<' '<<r<<' ';
		l=sm,r=R[i]-L[i]-1-sm+1,k=sm*a[i],d=0;
		if(l+1<=r) add(1,1,maxn-1,l+1,r,d);
		add(1,1,maxn-1,l,l,k);
		add(1,1,maxn-1,r+1,r+1,-k-d*(r-l));
//		cout<<l<<' '<<r<<' ';
		l=0,r=0;
		if(sm!=1) {
			l=R[i]-L[i]-sm+1,r=R[i]-L[i]-1,k=(sm-1)*a[i],d=-a[i];
			if(l+1<=r) add(1,1,maxn-1,l+1,r,d);
			add(1,1,maxn-1,l,l,k);
			add(1,1,maxn-1,r+1,r+1,-k-d*(r-l));
		}
//		cout<<l<<' '<<r<<'\n';
	}
	For(i,1,n) cout<<query(1,1,maxn-1,1,i)<<'\n';
}

signed main() {
//	freopen("data.in","r",stdin);
//	freopen("myans.out","w",stdout);
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);
	double stt=clock();
	int _=1;
//	_=read();
//	cin>>_;
	For(i,1,_) {
		work();
	}
	cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
	return 0;
}
/*
x 可以对最多长度为 k 的串产生贡献,那么 x 产生的贡献会像这样:

长度 贡献
1    x
2    2x
3    3x
...  ...
k-2  3x
k-1  2x
k    x
*/
posted @ 2025-05-24 21:35  coding_goat_qwq  阅读(34)  评论(0)    收藏  举报