樹蕨結構題錦——莫隊
阿新 • • 發佈:2021-07-25
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; }