1. 程式人生 > 實用技巧 >lagrange-CSP.ac

lagrange-CSP.ac

題目

有兩個序列長\(n\)\(A_i\)\(B_i\),需要進行兩種操作,共進行\(q\)

\(查詢區間 \sum_{l\leq i<j\leq 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,1\leq A_i,x,B_i,x,y\leq 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(n\sqrt 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;
 }