P5268 [SNOI2017] 一个简单的询问
P5268 [SNOI2017] 一个简单的询问
题目描述
给你一个长度为
数据范围
对于
Solution:
首先我们不难发现我们可以用一个数组
也就是说,我们只需要分别求出这四个值然后拼在一起就好了。
然后我们考虑如何维护这四个值:
假设现在有一个区间
当我们扩展区间至
Code:
#include<bits/stdc++.h> #define ll long long const int N=5e4+5; using namespace std; int a[N],b[N],cntl[N],cntr[N],blc[N]; ll ans[N]; int n,m,S,tot; int l,r; ll tmp; inline void move_l(int x) { if(x==1){cntl[a[++l]]++;tmp+=cntr[a[l]];} else {cntl[a[l]]--;tmp-=cntr[a[l--]];} } inline void move_r(int x) { if(x==1){cntr[a[++r]]++;tmp+=cntl[a[r]];} else {cntr[a[r]]--;tmp-=cntl[a[r--]];} } struct task{ int l,r,id,k; bool operator <(const task &t)const{ return blc[l]==blc[t.l] ? (blc[l]&1 ? r<t.r : t.r<r) : l<t.l; } }t[N<<2]; void work() { cin>>n;S=sqrt(N); for(int i=1;i<=n;i++) { scanf("%d",&a[i]);b[i]=a[i]; blc[i]=i/S; } sort(b+1,b+1+n); for(int i=1;i<=n;i++) { a[i]=lower_bound(b+1,b+1+n,a[i])-b; } cin>>m; for(int i=1,l,r,L,R;i<=m;i++) { scanf("%d%d%d%d",&l,&r,&L,&R); l--,L--; t[++tot]={r,R,i,1}; t[++tot]={r,L,i,-1}; t[++tot]={l,R,i,-1}; t[++tot]={l,L,i,1}; } for(int i=1;i<=tot;i++)if(t[i].l>t[i].r)swap(t[i].l,t[i].r); sort(t+1,t+1+tot); for(int i=1;i<=tot;i++) { while(t[i].l<l)move_l(-1); while(l<t[i].l)move_l(1); while(r<t[i].r)move_r(1); while(t[i].r<r)move_r(-1); ans[t[i].id]+=tmp*t[i].k; } for(int i=1;i<=m;i++) { printf("%lld\n",ans[i]); } } int main() { //freopen("P5268.in","r",stdin);freopen("P5268.out","w",stdout); work(); return 0; }