题解 ABC455F - Merge Slimes 2
题解 ABC455F - Merge Slimes 2
其他题
自评:下位绿。
手速场毁我青春,只有不到
简要题意
有初值为
将区间内的各数进行合并,两个数
x,y 合并时得到一个新数x+y 并产生xy 的贡献,求合并成一个数后最大的总贡献。
后面的询问只继承前面的区间加,不继承前面的合并。
数据范围:
做法
首先请准备一句尽可能难听的粗话。
考虑合并问题的答案什么时候是最大的。你惊奇地发现,事实上由于合并完后的数是两数相加,所以每个数最后都会和其他所有数乘一遍,与具体的合并顺序无关。好的现在可以大声地喊出刚才准备的粗话来赞颂出题人的功德了。
于是我们需要求出每个数与其他数都乘一遍的答案。如果加上自己乘自己的贡献,那答案显然是区间和的平方;故实际的答案是区间和的平方 减去 区间每个数的平方的和。前者是线段树板子,后者其实也是,不过打 tag 的时候要用到完全平方公式
复杂度
//Please ignore those headfiles.I write them just because
//DEV-C++ won't support completion if i use <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<unordered_map>
#include<set>
#include<queue>
#define ll long long
#define ull unsigned long long
#define lf double
#define ld long double
#define LL __int128
#define ui unsigned int
using namespace std;
const ll mod=998244353;
struct node{
ll ls,rs,s,ss,tag;
};
node t[200010];
ll n,q,u,v,w,p=2;
inline ll ksm(ll x,ll y){
if(y==0)return 1;
if(y==1)return x;
ll tmp=ksm(x,y>>1);
return y&1?tmp*tmp%mod*x%mod:tmp*tmp%mod;
}
void build(ll now,ll l,ll r){
if(l==r){
return ;
}
ll mid=(l+r>>1);
t[now].ls=(p++);
build(t[now].ls,l,mid);
t[now].rs=(p++);
build(t[now].rs,mid+1,r);
}
void pushdown(ll now,ll l,ll r){
ll mid=(l+r>>1);
t[t[now].ls].ss+=t[now].tag*t[now].tag%mod*(mid-l+1)%mod+t[now].tag*t[t[now].ls].s*2%mod;
t[t[now].ls].s+=t[now].tag*(mid-l+1)%mod;
t[t[now].ls].tag+=t[now].tag;
t[t[now].rs].ss+=t[now].tag*t[now].tag%mod*(r-mid)%mod+t[now].tag*t[t[now].rs].s*2%mod;
t[t[now].rs].s+=t[now].tag*(r-mid)%mod;
t[t[now].rs].tag+=t[now].tag;
t[t[now].ls].ss%=mod;
t[t[now].ls].s%=mod;
t[t[now].ls].tag%=mod;
t[t[now].rs].ss%=mod;
t[t[now].rs].s%=mod;
t[t[now].rs].tag%=mod;
t[now].tag=0;
}
void upd(ll now,ll l,ll r,ll L,ll R,ll c){
pushdown(now,l,r);
if(l>=L&&r<=R){
t[now].ss+=(r-l+1)*c%mod*c%mod+t[now].s*c*2%mod;
t[now].s+=(r-l+1)*c%mod;
t[now].tag+=c;
t[now].s%=mod;
t[now].ss%=mod;
t[now].tag%=mod;
return ;
}
ll mid=(l+r>>1);
if(L<=mid){
upd(t[now].ls,l,mid,L,R,c);
}
if(R>mid){
upd(t[now].rs,mid+1,r,L,R,c);
}
t[now].s=t[t[now].ls].s+t[t[now].rs].s;
t[now].ss=t[t[now].ls].ss+t[t[now].rs].ss;
t[now].s%=mod;
t[now].ss%=mod;
}
ll querys(ll now,ll l,ll r,ll L,ll R){
pushdown(now,l,r);
if(l>=L&&r<=R){
return t[now].s;
}
ll mid=(l+r>>1),ans=0;
if(L<=mid){
ans+=querys(t[now].ls,l,mid,L,R);
}
if(R>mid){
ans+=querys(t[now].rs,mid+1,r,L,R);
}
return ans%mod;
}
ll queryss(ll now,ll l,ll r,ll L,ll R){
pushdown(now,l,r);
if(l>=L&&r<=R){
return t[now].ss;
}
ll mid=(l+r>>1),ans=0;
if(L<=mid){
ans+=queryss(t[now].ls,l,mid,L,R);
}
if(R>mid){
ans+=queryss(t[now].rs,mid+1,r,L,R);
}
return ans%mod;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>q;
build(1,1,n);
while(q--){
cin>>u>>v>>w;
upd(1,1,n,u,v,w);
ll tmp=querys(1,1,n,u,v);
cout<<(tmp*tmp%mod-queryss(1,1,n,u,v)+mod)%mod*ksm(2,mod-2)%mod<<endl;
}
return 0;
}