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
*/
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/18894727

浙公网安备 33010602011771号