ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树蕨结构题锦——莫队

2021-07-25 11:01:18  阅读:134  来源: 互联网

标签:cnt return get int sum 题锦 -- 莫队 结构


 

zoto【来源:2021杭电多校第一场的第10题】

题目:

Problem Description You are given an array fx.
For each i(1<=i<=n) , we use a point (i,fx[i]) in XoY coordinate plane to described it.
You are asked to answer m queries, in each query there will be a rectangle and you need to count how many different y-cooordinate (of the points mentioned above) in the queried rectangle.   Input The first line contains an integer T(1<=T<=5) representing the number of test cases.
For each test case , there are two integers n,m(1<=n<=100000,1<=m<=100000) in the first line.
Then one line contains n integers fx[i](0<=fx[i]<=100000)
Each of the next m lines contain four integers x0,y0,x1,y1(1<=x0<=x1<=n,0<=y0<=y1<=100000) which means matrix's lower-leftmost cell is (x0,y0) and upper-rightest cell is (x1,y1).   Output For each test case print a single integer in a new line.   Sample Input 1 4 2 1 0 3 1 1 0 4 3 1 0 4 2   Sample Output 3 2   Source 2021“MINIEYE杯”中国大学生算法设计超级联赛(1)

分析:

> 题目:
> T组测试数据, T大小为5:
> 给定n个坐标,横坐标为从1到n,对应纵坐标为fx[i],共有m此询问,其中n,m,fx大小都是1e5
> 每次询问,查询一个以(x0,y0)为左下角,以(x1,y1)为右上角的矩形面积内,有多少个不同的fx

> 解决:
> T是T,m是1e5,那么,我们每次的查询操作的时间复杂度需要降到O(logn)才能合法,而且,只有查询没有修改,基础莫队便可以解决次题。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, len;
int w[N], cnt[N], sum[N], ans[N];
struct Query{
  int l, r, L, R, id;
}q[N];
int get(int x)
{
  return x / len;
}
bool cmp(const Query& a, const Query& b)
{
  int x = get(a.l), y = get(b.l);
  if (x != y) return x < y;
  return a.r < b.r;
  // if (x == y) return a.r < b.r;
  // return (x & 1) ? x > y : x < y;
}
void add(int x)
{
  // printf("del: x = %d, cnt[x] = %d\n", x, cnt[x]);
  //sum计算块内的节点数量,我们对y轴分块,计算的是fx的分块内的值
  if (!cnt[x]) sum[get(x)] ++;
  cnt[x] ++;
}
void del(int x)
{
  // printf("del: x = %d, cnt[x] = %d\n", x, cnt[x]);
  cnt[x] --;
  if (!cnt[x]) sum[get(x)] --;
}
int calc(int y)
{
  //计算y轴,从0到y的个数
  int res = 0;
  //sum代表y轴分块val的数量,res先求的是前缀和
  for (int i = 0; i < get(y); i ++ ) res += sum[i];
  //最上面的一点,这些不再整块内,暴力计算
  for (int i = get(y) * len; i <= y; i ++ ) res += (cnt[i] >= 1);
  return res;
}
void solve()
{
  memset(cnt, 0, sizeof cnt);
  memset(sum, 0, sizeof sum);
  scanf("%d%d", &n, &m);
  // len = sqrt(n);
  len = 131;
  for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
  for (int i = 0; i < m; i ++ )
  {
    int l, L, r, R; scanf("%d%d%d%d", &l, &L, &r, &R);
    q[i] = {l, r, L, R, i};
  }
  sort(q, q + m, cmp);
  for (int i = 0, l = 1, r = 0; i < m; i ++ )
  {
    // printf("q[i].l = %d, bottom = %d, q[i].r = %d, top = %d\n", q[i].l, q[i].L, q[i].r, q[i].R);
    // printf("del l ++ \n");
    while (l < q[i].l) del(w[l ++ ]);
    // printf("add -- l \n");
    while (l > q[i].l) add(w[-- l ]);
    // printf("add ++ r \n");
    while (r < q[i].r) add(w[++ r ]);
    // printf("del r -- \n");
    while (r > q[i].r) del(w[r -- ]);
    ans[q[i].id] = calc(q[i].R) - calc(q[i].L - 1);
  }
  for (int i = 0; i < m; i ++ ) printf("%d\n", ans[i]);
}
int main()
{
  int T = 1;
  cin >> T;
  while (T -- )
  {
    solve();
  }
  return 0;
}

  

 

标签:cnt,return,get,int,sum,题锦,--,莫队,结构
来源: https://www.cnblogs.com/Iamcookieandyou/p/15057252.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有