1. 程式人生 > 其它 >樹蕨結構題錦——莫隊

樹蕨結構題錦——莫隊

zoto【來源:2021杭電多校第一場的第10題】

題目:

Problem Description You are given an arrayfx.
For eachi(1<=i<=n), we use a point(i,fx[i])inXoYcoordinate plane to described it.
You are asked to answermqueries, 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 integerT(1<=T<=5)representing the number of test cases.
For each test case , there are two integersn,m(1<=n<=100000,1<=m<=100000)in the first line.
Then one line contains n integersfx[i](0<=fx[i]<=100000)
Each of the next m lines contain four integersx0,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;
}