洛谷P8421 [THUPC2022 决赛] rsraogps
给定三个序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an, b 1 , ⋯ , b n b_1,\cdots,b_n b1,⋯,bn, c 1 , ⋯ , c n c_1,\cdots,c_n c1,⋯,cn。
定义区间 [ l , r ] [l,r] [l,r]的价值为 a l , … , a r a_l,\dots,a_r al,…,ar按位与, b l , ⋯ , b r b_l,\cdots,b_r bl,⋯,br按位或, c l , ⋯ , c r c_l,\cdots,c_r cl,⋯,cr的最大公约数,这三者的乘积。
有 m m m次查询,每次查询给出区间 [ l , r ] [l,r] [l,r],查询满足 l ≤ l ′ ≤ r ′ ≤ r l\leq l'\leq r'\leq r l≤l′≤r′≤r的 [ l ′ , r ′ ] [l',r'] [l′,r′]的价值之和。
输出答案模 2 32 2^{32} 232后的值。
1 ≤ n ≤ 1 0 6 , 1 ≤ m ≤ 5 × 1 0 6 , 1 ≤ a i , b i , c i ≤ n , 1 ≤ l ≤ r ≤ n 1\leq n\leq 10^6,1\leq m\leq 5\times 10^6,1\leq a_i,b_i,c_i\leq n,1\leq l\leq r\leq n 1≤n≤106,1≤m≤5×106,1≤ai,bi,ci≤n,1≤l≤r≤n
我们先把询问离线下来,做扫描线,扫描 r r r。
设 A r , i = a i & a i + 1 & ⋯ & a r A_{r,i}=a_i\& a_{i+1}\&\cdots\&a_r Ar,i=ai&ai+1&⋯&ar, B r , i = b i ∣ b i + 1 ∣ ⋯ ∣ b r B_{r,i}=b_i|b_{i+1}|\cdots|b_r Br,i=bi∣bi+1∣⋯∣br, C r , i = gcd ( c i , c i + 1 , ⋯ , c r ) C_{r,i}=\gcd(c_i,c_{i+1},\cdots,c_r) Cr,i=gcd(ci,ci+1,⋯,cr)。
在扫描 r r r的时候,对于每个 i i i维护 s r , i = s r − 1 , i + ∑ j = 1 i A r , j × B r , j × C r , j s_{r,i}=s_{r-1,i}+\sum\limits_{j=1}^iA_{r,j}\times B_{r,j}\times C_{r,j} sr,i=sr−1,i+j=1∑iAr,j×Br,j×Cr,j,那么答案为 s r , r − s r , l − 1 s_{r,r}-s_{r,l-1} sr,r−sr,l−1。
然而,我们发现,如果存在一个位置 j j j,满足 A r , j = = A r − 1 , j A_{r,j}==A_{r-1,j} Ar,j==Ar−1,j,则 ∀ k ≤ j \forall k\leq j ∀k≤j,都满足 A r , k = = A r − 1 , k A_{r,k}==A_{r-1,k} Ar,k==Ar−1,k。也就是说,当 r r r右移一位时,有一部分 A A A不受影响, B B B和 C C C同理, A , B , C A,B,C A,B,C都不变的这部分对 s r , i s_{r,i} sr,i的增量是不变的。
我们可以从 i i i往前一个一个找,直到找到第一个满足 A r , j = = A r − 1 , j A_{r,j}==A_{r-1,j} Ar,j==Ar−1,j且 B B B和 C C C同样满足的位置 j j j。这样做一次看似是 O ( n ) O(n) O(n)的,但是 A r , i , B r , i , C r , i A_{r,i},B_{r,i},C_{r,i} Ar,i,Br,i,Cr,i在随着 i i i减小时,最多只会改变 O ( log n ) O(\log n) O(logn)次值,在最坏情况下,也只需要往前找 O ( log n ) O(\log n) O(logn)次,时间复杂度是 O ( log n ) O(\log n) O(logn)的。
设 a d i ad_i adi表示前 i i i个值在 r r r右移一位时对 s s s的增量(即 ∑ j = 1 i A r , j × B r , j × C r , j \sum\limits_{j=1}^iA_{r,j}\times B_{r,j}\times C_{r,j} j=1∑iAr,j×Br,j×Cr,j), l s t i lst_i lsti表示 A r , i , B r , i , C r , i A_{r,i},B_{r,i},C_{r,i} Ar,i,Br,i,Cr,i上次被修改的时间戳, v i v_i vi表示位置 i i i最后一次被修改前的贡献。对于当前的 r r r,找到满足上面条件的位置 j j j,并更新 j j j到 i i i之间的 v v v, a d ad ad和 l s t lst lst。
那么, s r , i = v i + ( r − l s t i ) × a d i s_{r,i}=v_i+(r-lst_i)\times ad_i sr,i=vi+(r−lsti)×adi,对于询问 l , r l,r l,r,答案为 s r , r − s r , l − 1 s_{r,r}-s_{r,l-1} sr,r−sr,l−1。
用 unsigned int \text{unsigned int} unsigned int即可解决模 2 32 2^{32} 232的问题。
可以参考代码,方便理解。
时间复杂度为 O ( n log n + m ) O(n\log n+m) O(nlogn+m)。
#include
using namespace std;
const int N=1000000,M=5000000;
int n,m,now,lst[N+5];
unsigned int a[N+5],b[N+5],c[N+5],v[N+5],ad[N+5],ans[M+5];
struct node{
int l,id;
};
vector<node>w[N+5];
unsigned int gcd(int i,int j){
while(j){
i%=j;swap(i,j);
}
return i;
}
unsigned int gt(int i){
return v[i]+ad[i]*(now-lst[i]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%u",&a[i]);
for(int i=1;i<=n;i++) scanf("%u",&b[i]);
for(int i=1;i<=n;i++) scanf("%u",&c[i]);
for(int i=1,l,r;i<=m;i++){
scanf("%d%d",&l,&r);
w[r].push_back((node){l,i});
}
for(int i=1;i<=n;i++){
int j=i-1;
while(j){
int v1,v2,v3;
v1=a[j]&a[j+1];
v2=b[j]|b[j+1];
v3=gcd(c[j],c[j+1]);
if(v1==a[j]&&v2==b[j]&&v3==c[j]) break;
a[j]=v1;b[j]=v2;c[j]=v3;
--j;
}
v[i]=gt(i-1);
for(int k=j+1;k<=i;k++){
v[k]=gt(k);
ad[k]=ad[k-1]+a[k]*b[k]*c[k];
lst[k]=now;
}
++now;
for(int k=0;k<w[i].size();k++){
ans[w[i][k].id]=gt(i)-gt(w[i][k].l-1);
}
}
for(int i=1;i<=m;i++){
printf("%u\n",ans[i]);
}
return 0;
}