男神zyh的青睐
作者:互联网
这道题与普通的莫队不一样的地方是,普通的莫队是求一个\([l,r]\)区间里面的贡献,但是这道题需要求两个区间贡献之间的积。
普通的莫队是二维的,对左端点进行分块,然后再在块内对右端点进行排序,复杂度为\(O(n^{\frac{3}{2}})\)。
但是本题的莫队是三维的,对左端点进行分块,然后再在块内对右端点进行分块,然后再在块内对时间 t 进行排序,可以证明当块的大小取\(n^\frac{2}{3}\)的时候,算法的总复杂度为\(O(n^\frac{5}{3})\)
可以利用容斥原理,将原本是四维的莫队,降为三维,把\((r_1-l_1)\times(r_2-l_2)\)变为\((r_2-l_2)\times[1,r]-(r_2-l_2)\times[1,l_1-1]\)
不过我也尝试了一下四维莫队的解法,复杂度为\(O(n^{\frac{7}{4}})\),大概是1e8,在经过亿点点优化之后,居然卡过去了。
三维写法:
// Created by CAD
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e4+5;
const int mod=1e9+7;
int belo[maxn];
struct query{
int l,r,id,t;
bool operator<(const query &q)const {
return belo[l]!=belo[q.l]?(belo[l]<belo[q.l]):(belo[r]!=belo[q.r]?(belo[r]<belo[q.r]):(t<q.t));
}
}q[maxn<<1];
int a[maxn],cnt1[maxn],cnt2[maxn],ans[maxn];
ll now;
ll d[maxn];
inline void add(int x){
now+=cnt1[a[x]];
now%=mod;
cnt2[a[x]]++;
}
inline void del(int x){
now-=cnt1[a[x]];
now%=mod;
cnt2[a[x]]--;
}
inline void ad(int x){
now+=cnt2[a[x]];
now%=mod;
cnt1[a[x]]++;
}
inline void de(int x){
now-=cnt2[a[x]];
now%=mod;
cnt1[a[x]]--;
}
ll qpow(ll x,ll n){
ll ans=1;
while(n>0){
if(n&1) ans=ans*x%mod;
x=x*x%mod,n>>=1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;cin>>n>>m;
int blo=pow(n,2/3.0);
for(int i=1;i<=n;++i){
cin>>a[i];
belo[i]=(i-1)/blo+1;
}
for(int i=1;i<=m;++i){
int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;
q[i*2-1]={l2,r2,-i,l1-1};
q[i*2]={l2,r2,i,r1};
d[i]=1ll*(r2-l2+1)*(r1-l1+1)%mod;
}
sort(q+1,q+2*m+1);
int l=1,r=0,t=0;
for(int i=1;i<=2*m;++i){
int ql=q[i].l,qr=q[i].r,qt=q[i].t;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(r>qr) del(r--);
while(t<qt) ad(++t);
while(t>qt) de(t--);
ans[abs(q[i].id)]+=q[i].id/abs(q[i].id)*now;
ans[abs(q[i].id)]%=mod;
}
for(int i=1;i<=m;++i){
cout<<1ll*(ans[i]+mod)%mod*qpow(d[i],mod-2)%mod<<endl;
}
return 0;
}
四维写法:
// Created by CAD
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e4+5;
const int mod=1e9+7;
int belo[maxn];
struct query{
int p[4],id;
bool operator<(const query &q)const {
for(int i=0;i<3;++i)
if(belo[p[i]]!=belo[q.p[i]]){
if(!i||belo[p[i-1]]&1)
return belo[p[i]]<belo[q.p[i]];
else
return belo[p[i]]>belo[q.p[i]];
}
if(belo[p[2]]&1)
return p[3]<q.p[3];
else return p[3]>q.p[3];
}
}q[maxn<<1];
int a[maxn],cnt[2][maxn],ans[maxn];
ll now;
ll d[maxn];
inline void add(int &x,int &i){
now+=cnt[i^1][x];
now%=mod;
++cnt[i][x];
}
inline void del(int &x,int &i){
now-=cnt[i^1][x];
now%=mod;
--cnt[i][x];
}
inline ll qpow(ll x,ll n){
ll ans=1;
while(n>0){
if(n&1) ans=ans*x%mod;
x=x*x%mod,n>>=1;
}
return ans;
}
int main() {
int n,m;scanf("%d%d",&n,&m);
int blo=pow(n,0.74);
for(int i=1;i<=n;++i){
scanf("%d",a+i);
belo[i]=(i-1)/blo+1;
}
for(int i=1;i<=m;++i){
int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
q[i]={l1,r1,l2,r2,i};
d[i]=1ll*(r2-l2+1)*(r1-l1+1)%mod;
}
sort(q+1,q+m+1);
int p[4]={1,0,0,0};
for(int i=1;i<=m;++i){
for(int j=0;j<2;++j){
int &l=p[j*2],&r=p[j*2+1];
int &ql=q[i].p[j*2],&qr=q[i].p[j*2+1];
while(l<ql) del(a[l++],j);
while(l>ql) add(a[--l],j);
while(r<qr) add(a[++r],j);
while(r>qr) del(a[r--],j);
}
ans[q[i].id]=now;
}
for(int i=1;i<=m;++i)
printf("%lld\n",1ll*(ans[i]+mod)%mod*qpow(d[i],mod-2)%mod);
return 0;
}
标签:青睐,int,zyh,--,ans,男神,莫队,id,mod 来源: https://www.cnblogs.com/CADCADCAD/p/14710663.html