这道题需要一些莫队算法的知识 定义记号f(A,B)表示询问区间A,B时的答案 用记号+表示集合的并 利用莫队算法我们可以计算出任意f(A,A)的值 不妨假设A=[l1,r1],B=[l2,r2],C=[r1+1,l2?1] 容易知道f(A,B)=f(A+B+C,A+B+C)+f(C,C)?f(A+C,A+C)?f(C+B,C+B) 因此一个询问被拆成四个可以用莫队算法做的询问 总的时间复杂度为O(msqrt(n))
(以上是官方题解)
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; typedef long long LL; const int N = 30000*4 + 10; int pos[N]; struct pp{ int l,r,id; int ans; }p[N]; int cmp(pp a,pp b){ if(pos[a.l]==pos[b.l]) return a.r < b.r; return a.l < b.l; } int cmp2(pp a,pp b){ return a.id < b.id; } struct que{ int l1,l2,r1,r2; }q[N]; int block,n,k,m,num; int a[N],cnt[N],answer; LL x; map<LL,int> mm; void update(int x,int v){ int val = k - a[x]; if(val <= 0) return ; answer += cnt[val]*v; cnt[a[x]] += v; } void solve(){ int l,r; answer = 0; for(int i=1,l=1,r=0;i<=num;i++){//按块进行更新 for(;r<p[i].r;r++) update(r+1,1); for(;r>p[i].r;r--) update(r,-1); for(;l<p[i].l;l++) update(l,-1); for(;l>p[i].l;l--) update(l-1,1); p[i].ans = answer; } } int main(){ while(scanf("%d",&n)!=EOF){ mm.clear(); num = 0; block = (int)sqrt(n)+1; for(int i=1;i<=n;i++) pos[i] = i/block + 1; scanf("%d",&k); memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(int i=1;i<=m;i++){ int l1,l2,r1,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2); q[i].l1 = l1 , q[i].r1 = r1 , q[i].l2 = l2 , q[i].r2 = r2; p[++num].l = l1 , p[num].r = l2-1 ; x = l1*40000+(l2-1); mm[x] = num; p[num].id = num; p[++num].l = r1+1 , p[num].r = r2 ; x = (r1+1)*40000+r2; mm[x] = num; p[num].id = num; if(l2-1 >= r1+1){ p[++num].l = r1+1 , p[num].r = l2-1 ; x = (r1+1)*40000+(l2-1); mm[x] = num; p[num].id = num; } p[++num].l = l1 , p[num].r = r2 ; x = l1*40000+r2; mm[x] = num; p[num].id = num; } sort(p+1,p+1+num,cmp); solve(); sort(p+1,p+1+num,cmp2); for(int i=1;i<=m;i++){ int l1,l2,r1,r2; l1 = q[i].l1 , l2 = q[i].l2 , r1 = q[i].r1 , r2 = q[i].r2 ; LL ans = 0; x = l1*40000+r2; ans += p[mm[x]].ans; if(l2-1>=r1+1){ x = (r1+1)*40000+(l2-1); ans += p[mm[x]].ans; } x = (r1+1)*40000+r2; ans -= p[mm[x]].ans; x = l1*40000+(l2-1); ans -= p[mm[x]].ans; printf("%lld\n",ans); } } return 0; }
时间: 2024-10-16 12:39:32