题解:[ARC126E] Infinite Operations
题意分析
考虑极限 \(\displaystyle\lim_{n\rightarrow\infty}f(n)\) 的取值。显然是一个可以由 \(a_1,a_2,\cdots,a_n\) 确定的取值。
答案与 \(a_1,a_2,\cdots,a_n\) 顺序无关,不妨钦定 \(a_1\leq a_2\leq\cdots\leq a_n\)。
记选择 \(a_i+2x\leq a_j\) 做一次操作为 \((i,j,x)\)。
考虑单次操作 \((i,j,x)\) 显然存在一种最优策略,考虑什么样是最优的。
钦定 \(x,j\) 不变,如果先操作 \((j-1,j,x)\),可以获得 \(x\) 的贡献,且 \(i\sim j-1\) 之间还有可能继续贡献,因此对于确定的 \(i,j,x\) 这样最优。
因而单次最优操作一定是相邻的操作,又因为最终所有数都会变成平均数 \(\displaystyle\overline a=\dfrac1n\sum_{i=1}^na_i\),考虑拆贡献。
将一次操作视为从后往前转移的,\((i-1,i,x)\) 操作的 \(x\) 之和即为 \(a_i\sim a_n\) 减量的总和,即 \(\displaystyle\sum_{j=i}^n\left(a_j-\overline a\right)\)。
最终单次询问答案为:
考虑到我们钦定了 \(a_1\leq a_2\leq\cdots\leq a_n\),实际过程中不能如此,记 \(\operatorname{rank}(i)\) 为 \(a_i\) 的排名(相同元素的排名不同),有答案为:
平衡树维护序列即可。考虑左子树对于右子树和根的排名的贡献为左子树大小即可维护。
具体而言,考虑如何维护节点 \(p\) 的信息,记其左右子节点分别为 \(\operatorname{lChild}(p),\operatorname{rChild}(p)\)。
对于节点 \(x\),记子树大小为 \(\operatorname{size}(x)\),权值为 \(\operatorname{value}(x)\),子树权值和为 \(\operatorname{sum}(x)\),答案为 \(\operatorname{ans}(x)\),单次询问答案即 \(\operatorname{ans}(\textit{root})\)。
则更新节点 \(\operatorname{ans}(p)\) 即:
其实就是考虑对排名拆贡献,左子树对于右子树和根的排名的贡献都是左子树大小。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<random>
using namespace std;
typedef long long ll;
constexpr const int N=3e5,Q=3e5,V=1e9,P=998244353,inv2=499122177;
mt19937 Rand(time(0));
int n,a[N+1];
int root;
struct FHQTreap{
int size;
struct node{
int value,sum,ans,size,rand;
int lChild,rChild;
}t[N+Q+1];
FHQTreap(){
size=root=0;
}
int create(int x){
t[++size]={x,x%P,x%P,1,Rand()};
return size;
}
void up(int p){
t[p].size=t[t[p].lChild].size+t[t[p].rChild].size+1;
t[p].sum=(1ll*t[t[p].lChild].sum+t[p].value+t[t[p].rChild].sum)%P;
t[p].ans=(1ll*t[t[p].lChild].ans+t[t[p].rChild].ans+(t[t[p].lChild].size+1ll)*(t[p].value+t[t[p].rChild].sum)%P)%P;
}
void split(int p,int x,int &l,int &r){
if(!p){
l=r=0;
return;
}
if(t[p].value<=x){
l=p;
split(t[p].rChild,x,t[p].rChild,r);
}else{
r=p;
split(t[p].lChild,x,l,t[r].lChild);
}
up(p);
}
int merge(int l,int r){
if(!l||!r){
return l|r;
}
if(t[l].rand<t[r].rand){
t[l].rChild=merge(t[l].rChild,r);
up(l);
return l;
}else{
t[r].lChild=merge(l,t[r].lChild);
up(r);
return r;
}
}
void insert(int x){
int l,r,p;
split(root,x,l,r);
root=merge(merge(l,create(x)),r);
}
void erase(int x){
int l,r,p;
split(root,x,l,r);
split(l,x-1,l,p);
p=merge(t[p].lChild,t[p].rChild);
root=merge(merge(l,p),r);
}
int sum(){
return t[root].sum;
}
int ans(){
return t[root].ans;
}
}t;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int q,sum=0;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i];
t.insert(a[i]);
}
while(q--){
int x,y;
cin>>x>>y;
t.erase(a[x]);
a[x]=y;
t.insert(a[x]);
int ans=(t.ans()-(n+1ll)*inv2%P*t.sum()%P)%P;
if(ans<0){
ans+=P;
}
cout<<ans<<'\n';
}
cout.flush();
/*fclose(stdin);114514
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号