题目
有两个序列长(n)为(A_i),(B_i),需要进行两种操作,共进行(q)次
(查询区间 sum_{lleq i<jleq r}{(A_iB_j - A_jB_i)}的值,结果对 998244353 取模)
(把 (A_i , B_i) 修改为 (x,y))
对于(20 \%)的数据,(n,q≤200)
对于(40 \%)的数据,(n,q≤2000)
对于另外(30 \%)的数据,仅有操作查询操作
对于(100 \%)的数据,(n,q≤500000,1leq A_i,x,B_i,x,yleq 10^9)
考场思路
(8:30)开考,写了5分钟文化课作业才意识到发卷了
开卷看(T1),本来想手推出式子啥的,结果能力有限(()毕竟不是数竞
然后打了个表,秒切。
(15)分钟开(T2)
感觉可做,但完全想不到优化的策略,打了个暴力,写了个对拍,溜了溜了
去(T3),看到这个题,直接联想线段树维护,但困难出现在区间合并问题上,想了半个小时无果,放弃T3,写了个(20)分暴力溜了,
开(T4),
我(:******????),直接联想到不可做
转回去看(T2),反复想了想,这不是以我目前实力可以解决的
再看(T3),已经(11:00),已经放弃(T3)正解,开始思考查询做法(事实证明写了也没用
因为只有查询,所以可以考虑离线做法,然后我脑袋一热,尝试写昨天仅仅听过一遍的莫队,然后在最后(20)分钟写出来了,又花时间对了对拍,把部分分草草合并交了
下午查成绩
(T1:100pts)
(T2:30pts)
(T3:0)
(T4:0)
(Tot = 100pts + 30pts + 0pts+0pts)
我(T3)挂了 (?!?!) 我对拍了呀
讲评的时候我才知道,(30)分取模出现负数了,没有修成正数,挂了
莫队就更惨了,所有询问做法全部是在大于(1e5)的范围内进行的,(O(nsqrt n))过不去……
莫队
一种离线算法,被称为“优雅的暴力”
正常莫队不支持修改,且要求支持(O(1))快速单点插入、删除
先对所有询问按照左端点分块,对所有询问先按左端点所在的块排序,再按照右端点排序,
然后对每个询问,移动左右指针,并维护当前区间信息,移动指针时要求进行(O(1))不断更新信息
代码
lagrange代码,显然提交它并不会得分,但毕竟跑的更快一点点
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define mod 998244353
#define int long long
const int p=5e5+5;
struct node{
int x,y;
};
struct qry{
int l,r;
int place;
int id;
};
qry query[p];
node mum[p];
int suma;
int sumb;
int sumx;
int n;
int q;
inline bool cmp(qry a,qry b)
{
if(a.place != b.place)
return a.place < b.place;
else
{
return a.r < b.r;
}
}
int l=1,r = 0;
inline int sum(int point)
{
suma += mum[point].x*mum[point].x;
suma%=mod;
sumb += mum[point].y*mum[point].y;
sumb%=mod;
sumx += 2*(mum[point].x*mum[point].y)%mod;
sumx%=mod;
}
inline int arcsum(int point)
{
suma -= mum[point].x*mum[point].x;
suma %= mod;
sumb -= mum[point].y*mum[point].y;
sumb %= mod;
sumx -= 2*(mum[point].x*mum[point].y%mod);
sumx %= mod;
}
int ans[p];
inline int addrj(int point)
{
int aux=0;
if(l== r)
{
return 0;
}
aux += (suma*(mum[point].y*mum[point].y%mod)% mod)%mod;
aux -= (sumx*(mum[point].x * mum[point].y%mod)%mod)%mod;
aux += (sumb*(mum[point].x*mum[point].x%mod)%mod)%mod;
return (aux%mod);
}
inline void solve()
{
int now = 0;
for(int i=1;i<=q;i++)
{
int ql = query[i].l , qr = query[i].r;
while(r < qr) r++,now += addrj(r),now%=mod,sum(r);
while(r > qr) arcsum(r),now -= addrj(r),now%=mod,r--;
while(l < ql) arcsum(l),now -= addrj(l),now%=mod,l++;
while(l > ql) l--,now += addrj(l),now%=mod,sum(l);
ans[query[i].id] = (now+mod)%mod;
}
}
signed main()
{
ios_base::sync_with_stdio(false);
cout.tie(NULL);
cin.tie(NULL);
cin>>n>>q;
const int T=sqrt(n);
for(int i=1;i<=n;i++)
{
cin>>mum[i].x;
}
for(int i=1;i<=n;i++)
{
cin>>mum[i].y;
}
for(int i=1,op;i<=q;i++)
{
cin>>op;
if(op == 1)
{
cin>>query[i].l;
query[i].place = (query[i].l+1)/T;
cin>>query[i].r;
query[i].id = i;
}
}
sort(query+1,query+1+q,cmp);
solve();
for(int i=1;i<=q;i++) cout<<ans[i]<<endl;
}