题目描述

给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出
get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。

输入

第一行,一个数字N,表示序列长度。
第二行,N个数字,表示a1~aN
第三行,一个数字Q,表示询问个数。
第4~Q+3行,每行四个数字l1,r1,l2,r2,表示询问。
N,Q≤50000
N1≤ai≤N
1≤l1≤r1≤N
1≤l2≤r2≤N
注意:答案有可能超过int的最大值

输出

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

样例输入

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

样例输出

4
1


题解

莫队算法

(为了方便,以下使用$S_x(l,r)$代替$get(l,r,x)$)

题目一眼莫队,不过由于一个询问有4个参数,不能直接处理。

考虑将询问拆成前缀相减的形式,即:

$\ \ \ \ \sum\limits_xS_x(l_1,r_1)·S_x(l_2,r_2)\\=\sum\limits_{x}(S_x(1,r_1)-S_x(1,l_1-1))·(S_x(1,r_2)-S_x(1,l_2-1))\\=\sum\limits_{x}(S_x(1,r_1)·S_x(1,r_2)-S_x(1,l_1-1)·S_x(1,r_2)--S_x(1,r_1)·S_x(1,l_2-1)+S_x(1,l_1-1)·S_x(1,l_2-1))\\=Q(r_1,r_2)-Q(l_1-1,r_2)-Q(r_1,l_2-1)+Q(l_1-1,l_2-1)$

其中:

$Q(a,b)=\sum\limits_{x}S_x(1,a)·S_x(1,b)$

于是就可以把每个询问拆成4个,使用莫队算法分别计算对每个答案的贡献即可。

注意当$a$或$b$中某一个为0时的情况需要过滤掉,否则会加入不存在的位置导致挂掉。

时间复杂度$O(n\sqrt{4m})$

#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 50010
using namespace std;
typedef long long ll;
int si , v[N] , cl[N] , cr[N] , tot;
ll ans[N];
struct data
{
int l , r , flag , id;
data() {}
data(int a , int b , int c , int d) {l = min(a , b) , r = max(a , b) , flag = c , id = d;}
bool operator<(const data &a)const {return (l - 1) / si == (a.l - 1) / si ? r < a.r : (l - 1) / si < (a.l - 1) / si;}
}a[N << 2];
int main()
{
int n , m , i , x1 , y1 , x2 , y2 , lp = 0 , rp = 0;
ll now = 0;
scanf("%d" , &n) , si = (int)sqrt(n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]);
scanf("%d" , &m);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%d%d%d%d" , &x1 , &y1 , &x2 , &y2) , a[++tot] = data(y1 , y2 , 1 , i);
if(x1 > 1) a[++tot] = data(x1 - 1 , y2 , -1 , i);
if(x2 > 1) a[++tot] = data(y1 , x2 - 1 , -1 , i);
if(x1 > 1 && x2 > 1) a[++tot] = data(x1 - 1 , x2 - 1 , 1 , i);
}
sort(a + 1 , a + tot + 1);
for(i = 1 ; i <= tot ; i ++ )
{
while(lp < a[i].l) lp ++ , now += cr[v[lp]] , cl[v[lp]] ++ ;
while(rp < a[i].r) rp ++ , now += cl[v[rp]] , cr[v[rp]] ++ ;
while(lp > a[i].l) cl[v[lp]] -- , now -= cr[v[lp]] , lp -- ;
while(rp > a[i].r) cr[v[rp]] -- , now -= cl[v[rp]] , rp -- ;
ans[a[i].id] += a[i].flag * now;
}
for(i = 1 ; i <= m ; i ++ ) printf("%lld\n" , ans[i]);
return 0;
}

最新文章

  1. android给View设置边框 填充颜色 弧度
  2. java第四次作业
  3. SQLite常用语句
  4. Codeforces Round #264 (Div. 2) C
  5. SSH 两个表全套增删改(运动员住宿管理)
  6. (简单) POJ 3076 Sudoku , DLX+精确覆盖。
  7. 随心测试_软测基础_004&lt;测试人员工作职责&gt;
  8. 基于 CODING 的 Spring Boot 持续集成项目
  9. Spark大型电商项目实战-及其改良之番外(1)-将spark前端页面效果高效拷贝至博客
  10. XP下 无法定位程序输入点WSAPoll于动态链接库ws2_32.dll 的解决办法
  11. bzoj1997 [HNOI2010]平面图判定Plana
  12. php导出excel不使用科学计数法
  13. homebrew 更改镜像,进行成功安装
  14. 设计模式--观察者模式Observer(对象行为型)
  15. maven dependcymanage作用在父类里面定义依赖包 子类不会自动继承需要主动使用 这样解决了父类引用任意包 子类就会引用的问题
  16. 转:MySQL如何修改密码
  17. svg绘图工具raphael.js的使用
  18. Daily Scrum 11.18
  19. oracle存储过程和游标参考
  20. 颤振错误:当前Flutter SDK版本为2.1.0-dev.0.0.flutter-be6309690f?

热门文章

  1. [javaSE] 集合框架(ArrayList,LinkedList,Vector)
  2. C语言读取配置文件
  3. 面向连接的传输TCP(一)
  4. Linux下socket通信和epoll
  5. apply、call、bind有什么区别?
  6. HTML5之新增的属性和废除的属性 (声明:内容节选自《HTML 5从入门到精通》)
  7. 线上Bug修复流程
  8. Spring Boot&mdash;06集成前端模板thymeleaf
  9. Android 自定义AlertDialog(退出提示框)
  10. linux 链接命令