[BZOJ5016][Snoi2017]一个简单的询问

Time Limit: 30 Sec
Memory Limit: 512 MB

Description
给你一个长度为 N N N的序列 a i a_i ai 1 ≤ i ≤ N 1≤i≤N 1iN q q q组询问,每组询问读入 l 1 , r 1 , l 2 , r 2 l_1,r_1,l_2,r_2 l1,r1,l2,r2,需输出
在这里插入图片描述
g e t ( l , r , x ) get(l,r,x) get(l,r,x)表示计算区间 [ l , r ] [l,r] [l,r]中,数字 x x x出现了多少次。

Input
第一行,一个数字 N N N,表示序列长度。
第二行, N N N个数字,表示 a 1 ~ a N a_1~a_N a1aN
第三行,一个数字 Q Q Q,表示询问个数。
4 ~ Q + 3 4~Q+3 4Q+3行,每行四个数字 l 1 , r 1 , l 2 , r 2 l_1,r_1,l_2,r_2 l1,r1,l2,r2,表示询问。
N , Q ≤ 50000 N,Q≤50000 N,Q50000
1 ≤ a i ≤ N 1≤a_i≤N 1aiN
1 ≤ l 1 ≤ r 1 ≤ N 1≤l_1≤r_1≤N 1l1r1N
1 ≤ l 2 ≤ r 2 ≤ N 1≤l_2≤r_2≤N 1l2r2N
注意:答案有可能超过int的最大值

Output
对于每组询问,输出一行一个数字,表示答案

Sample Input

5
1 1 1 1 1
2
1 2 3 4
1 1 4 4

Sample Output

4
1

题解:
在这里插入图片描述这个玩意儿
我们可以设为 r e s ( l 1 , r 1 , l 2 , r 2 ) res(l_1,r_1,l_2,r_2) res(l1,r1,l2,r2)
那么
r e s ( l 1 , r 1 , l 2 , r 2 ) res(l_1,r_1,l_2,r_2) res(l1,r1,l2,r2) = r e s ( 1 , r 1 , 1 , r 2 ) res(1,r_1,1,r_2) res(1,r1,1,r2)- r e s ( 1 , l 1 − 1 , 1 , r 2 ) res(1,l_1-1,1,r_2) res(1,l11,1,r2)- r e s ( 1 , r 1 , 1 , l 2 − 1 ) res(1,r_1,1,l_2-1) res(1,r1,1,l21)+ r e s ( 1 , l 1 − 1 , 1 , l 2 − 1 ) res(1,l_1-1,1,l_2-1) res(1,l11,1,l21)
好了那么我们把一个询问拆成四个区间了,就可以莫队了。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define ll long long
using namespace std;
int c1[50004],c2[50004];
int n,a[50004],q,cnt;
int belong[50004];
struct ask{
    int sit;
    int _1,_2,k;
}qu[200004];
ask makeq(int x,int y,int sit,int k){
    ask T;
    T.sit=sit;T._1=x;T._2=y;T.k=k;
    return T;
}
inline bool dex(ask A,ask B){
    return belong[A._1]==belong[B._1]?A._2<B._2:belong[A._1]<belong[B._1];
}
ll ans[50004];
void work(){
     sort(qu+1,qu+cnt+1,dex);
     int o_1=0,o_2=0;
     c1[0]=1;
     c2[0]=1;
     ll val=0;
     for(int i=1;i<=cnt;i++){
         while(o_1<qu[i]._1){
            o_1++;
            c1[a[o_1]]++;
            val+=c2[a[o_1]];
         }
         while(o_1>qu[i]._1){
            val-=c2[a[o_1]];
            c1[a[o_1]]--;
            o_1--;
         }
         while(o_2<qu[i]._2){
            o_2++;
            c2[a[o_2]]++;
            val+=c1[a[o_2]];
         }
         while(o_2>qu[i]._2){
            val-=c1[a[o_2]];
            c2[a[o_2]]--;
            o_2--;
         }
         ans[qu[i].sit]+=val*qu[i].k;
     }
}
int w33ha(){
    cnt=0;
    memset(c1,0,sizeof(c1));
    memset(c2,0,sizeof(c2));
    memset(ans,0,sizeof(ans));
    a[0]=0;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int block=sqrt(1.0*n);
    for(int i=1;i<=n;i++)belong[i]=(i-1)/block+1;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int l1,l2,r1,r2;
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        qu[++cnt]=makeq(r1,r2,i,1);
        qu[++cnt]=makeq(r1,l2-1,i,-1);
        qu[++cnt]=makeq(r2,l1-1,i,-1);
        qu[++cnt]=makeq(l1-1,l2-1,i,1);
    }
    work();
    for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
    return 0;
}
int LiangJiaJun(){
    while(scanf("%d",&n)!=EOF)w33ha();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值