洛谷P8421 [THUPC 2022 决赛] rsraogps

洛谷P8421 [THUPC 2022 决赛] rsraogps

P8421 [THUPC 2022 决赛] rsraogps - 洛谷

因为从一个点最多会变化 \(\log V\) 次(这三种操作都是这样),考虑扫描线,这样每次更新前面答案贡献时,就有可能做到 \(\log V\) 的时复。

我们将答案拆成前缀和的形式:考虑扫描线到了 \(j\)\(s_i\) 表示满足 \(l\le i,l \le r \le j\),这样,答案被拆成了 \(s_j - s_{l-1}\)(扫描线 \(j=r\))。

考虑扫描线 \(r \to r+1\),改变了什么。

定义 \(A_{l,r},B_{l,r},C_{l,r}\) 表示区间的与、或、最大公约数。

\(s_i\) 会增加 \(\sum_{j=1}^i [j,r+1]\) 的区间贡献,我们注意到对于一段区间 \([j,r] \to [j,r+1]\) 如果其 \(A,B,C\) 的值均不变,那么对于 \([j,r-1],[j,r],[j,r+1]\) 之间增加的值是相同的,即 \(A\times B \times C\)

如果其 \(A,B,C\) 任意一个改变了,那么从 \(r\) 向左直到 \(A,B,C\) 均不再改变,先增加之前的 \(s_i\),然后打上新的增加值 \(add_i\)

最后,对于 \(\sum_{j=1}^i [j,r+1]\) 的值,即 \(add_i\),为 \(a,b,c\) 的一段前缀和。

\(\Large \mathscr{Code}\)

#include<bits/stdc++.h>
#define int unsigned
using namespace std;
const int N = 1e6+100;
int n,m,a[N],b[N],c[N],val[N],add[N],nt[N],T,ans[N*5];
vector<pair<int,int>> scan[N];
int query(int x){
	return val[x] + add[x]*(T-nt[x]);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=n;i++) cin>>c[i];
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		scan[r].push_back({l,i});
	}
	for(int i=1;i<=n;i++){
		int tmp = i-1;
		while(tmp){
			int x = a[tmp]&a[tmp+1],y = b[tmp]|b[tmp+1],z = __gcd(c[tmp],c[tmp+1]);
			if(x==a[tmp] && y==b[tmp] && z==c[tmp]) break;
			a[tmp] = x,b[tmp] = y,c[tmp] = z;
			tmp--;
		}
		val[i] = query(i-1);
		for(int j=tmp+1;j<=i;j++){
			val[j] = query(j);
			nt[j] = T;
			add[j] = add[j-1]+a[j]*b[j]*c[j];
		}
		T++;
		for(auto e:scan[i]) ans[e.second] = query(i)-query(e.first-1);
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
	return 0;
}
posted @ 2025-10-05 08:15  OrangeRED  阅读(7)  评论(0)    收藏  举报