算法筆記--CDQ分治 && 總體二分

參考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fenhtml

前置技能:樹狀數組,線段樹,分治、歸併排序node

CDQ分治:ios

聽說是OI大佬陳丹琦發明的c++

1.三維偏序數組

思路:ide

第一維排序,第二維分治,第三維樹狀數組上查詢post

考慮分治時區間 [l, m] 對區間 [m+1, r] 的貢獻,由於第一維已經排好序,因此區間 [l, m] 的第一維小於區間 [m+1, r]的第一維優化

而後對於區間 [m+1, r]中的某個元素x,將區間 [l, m] 的第二維小於x的元素的按第三維的權值加入樹狀數組,spa

最後區間 [l, m] 對區間 x 的貢獻就是查詢樹狀數組中小於x第三維的個數.net

能夠邊進行分治邊進行歸併排序,樹狀數組要及時清空

經過畫圖咱們能夠發現,對於每一個位置,咱們在分治時,它以前的位置對它的貢獻都計算過了,因此這種方法是正確的。

由於遞歸的層數是log(n)層,再加上樹狀數組,因此時間複雜度是O(n*log(n)^2)

P3810 【模板】三維偏序(陌上花開) 

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5, M = 2e5 + 5;
struct Node {
    int x, y, z;
    int ans, cnt;
    bool operator < (const Node & rhs) const {
        if(x == rhs.x) {
            if(y == rhs.y) return z < rhs.z;
            else return y < rhs.y;
        }
        else return x < rhs.x;
    }
}a[N], tmp[N];
int bit[M], res[N], n, k, cnt = 0;
void add(int x, int a) {
    while(x <= k) bit[x] += a, x += x&-x;
}
int sum(int x) {
    int res = 0;
    while(x) res += bit[x], x -= x&-x;
    return res;
}
void cdq(int l, int r) {
    if(l == r) {
        a[l].ans += a[l].cnt-1;
        return ;
    }
    int m = l+r >> 1;
    cdq(l, m);
    cdq(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && a[p].y <= a[q].y) add(a[p].z, a[p].cnt), tmp[tp++] = a[p], ++p;
        a[q].ans += sum(a[q].z);
        tmp[tp++] = a[q];
        ++q;
    }
    for (int i = l; i < p; ++i) add(a[i].z, -a[i].cnt);
    while(p <= m) tmp[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = tmp[i];
}
int main() {
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
    sort(a+1, a+1+n);
    int now = 1;
    for (int i = 2; i <= n; ++i) {
        if(a[i].x == a[i-1].x && a[i].y == a[i-1].y && a[i].z == a[i-1].z) ++now;
        else {
            a[++cnt] = a[i-1];
            a[cnt].cnt = now;
            a[cnt].ans = 0;
            now = 1;
        }
    }
    a[++cnt] = a[n];
    a[cnt].cnt = now;
    a[cnt].ans = 0;
    cdq(1, cnt);
    for (int i = 1; i <= cnt; ++i) res[a[i].ans] += a[i].cnt;
    for (int i = 0; i < n; ++i) printf("%d\n", res[i]);
    return 0;
}

 例題1:CodeForces - 669E

思路:時間當作一個維度就轉換成了三維偏序了

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
struct node {
    int a, t, x, ans, id;
    bool operator < (const node & rhs) const {
        return id < rhs.id;
    } 
}a[N], tmp[N];
int n;
map<int, int> cnt;
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m);
    cdq(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && a[p].t <= a[q].t) {
            if(a[p].a == 1) cnt[a[p].x]++; 
            else if(a[p].a == 2) cnt[a[p].x]--;
            tmp[tp++] = a[p], ++p;
        }
        if(a[q].a == 3) a[q].ans += cnt[a[q].x];
        tmp[tp++] = a[q];
        ++q;
    }
    for (int i = l; i < p; ++i)  {
        if(a[i].a == 1) cnt[a[i].x]--; 
        else if(a[i].a == 2) cnt[a[i].x]++;
    }
    while(p <= m) tmp[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = tmp[i];
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d %d %d", &a[i].a, &a[i].t, &a[i].x), a[i].ans = 0, a[i].id = i;
    cdq(1, n);
    sort(a+1, a+1+n);
    for (int i = 1; i <= n; ++i) if(a[i].a == 3) printf("%d\n", a[i].ans);
    return 0;
} 
View Code

例題2:HDU - 5618

思路:因爲對於每一個點都要詢問,因此不能像陌上花開那樣縮點了,排序後把相同的點的貢獻先加上去

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
struct Node {
    int x, y, z, id;
    int cnt;
    bool operator < (const Node & rhs) const {
        if(x == rhs.x) {
            if(y == rhs.y) return z < rhs.z;
            else return y < rhs.y;
        }
        else return x < rhs.x;
    }
}a[N], tmp[N];
int bit[N], ans[N], n, cnt = 0;
void add(int x, int a) {
    while(x < N) bit[x] += a, x += x&-x;
}
int sum(int x) {
    int res = 0;
    while(x) res += bit[x], x -= x&-x;
    return res;
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m);
    cdq(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && a[p].y <= a[q].y) add(a[p].z, a[p].cnt), tmp[tp++] = a[p], ++p;
        ans[a[q].id] += sum(a[q].z);
        tmp[tp++] = a[q];
        ++q;
    }
    for (int i = l; i < p; ++i) add(a[i].z, -a[i].cnt);
    while(p <= m) tmp[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = tmp[i];
}
int T;
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z), a[i].id = i, a[i].cnt = 1, ans[i] = 0;
        sort(a+1, a+1+n);
        int now = 0;
        for (int i = n-1; i >= 1; --i) {
            if(a[i].x == a[i+1].x && a[i].y == a[i+1].y && a[i].z == a[i+1].z) ++now;
            else now = 0;
            ans[a[i].id] += now;
        }
        cdq(1, n);
        for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
    }
    return 0;
}
View Code

例題3:CodeChef - QRECT

思路:考慮用容斥,用總個數減去和橫縱座標和它不相交的個數,這樣咱們發現和它橫縱座標都不相交被減了兩次,也就是四個角上的矩形,四個角上的矩形的個數就是三維偏序問題

代碼:

#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define pb push_back
//head

const int N = 1e5 + 10, M = 2e5 + 5;
struct Node {
    int ty, x1, y1, x2, y2, id;
    int ans, cnt;
    bool operator < (const Node & rhs) const {
        return id < rhs.id;
    }
}a[N], aa[N], tmp[N];
vector<int> vx, vy;
int n, bit1[M], bit2[M], bit[M], p, pos[N], cnt = 0, now = 0;
char op[10];
void add(int x, int a, int *bit) {
    while(x < M) bit[x] += a, x += x&-x;
}
int sum(int x, int *bit) {
    int res = 0;
    while(x) res += bit[x], x -= x&-x;
    return res;
}
void init() {
    for (int i = 1; i < M; ++i) bit1[i] = bit2[i] = 0;
}
void cdq1(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq1(l, m);
    cdq1(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && aa[p].x1 < aa[q].x1) {
            if(aa[p].ty == 1) add(aa[p].y1, 1, bit);
            else if(aa[p].ty == 2) add(aa[p].y1, -1, bit);
            tmp[tp++] = aa[p];
            ++p;
        }
        if(aa[q].ty == 3) {
            aa[q].ans += sum(aa[q].y1-1, bit);
        }
        tmp[tp++] = aa[q];
        ++q;
    }
    for (int i = l; i < p; ++i) if(aa[i].ty == 1) add(aa[i].y1, -1, bit); else if(aa[i].ty == 2) add(aa[i].y1, 1, bit);
    while(p <= m) tmp[tp++] = aa[p], ++p;
    for (int i = l; i <= r; ++i) aa[i] = tmp[i];
}

void cdq2(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq2(l, m);
    cdq2(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && aa[p].x1 > aa[q].x1) {
            if(aa[p].ty == 1) add(aa[p].y1, 1, bit);
            else if(aa[p].ty == 2) add(aa[p].y1, -1, bit);
            tmp[tp++] = aa[p];
            ++p;
        }
        if(aa[q].ty == 3) {
            aa[q].ans += sum(M-1, bit) - sum(aa[q].y1, bit);
        }
        tmp[tp++] = aa[q];
        ++q;
    }
    for (int i = l; i < p; ++i) if(aa[i].ty == 1) add(aa[i].y1, -1, bit); else if(aa[i].ty == 2) add(aa[i].y1, 1, bit);
    while(p <= m) tmp[tp++] = aa[p], ++p;
    for (int i = l; i <= r; ++i) aa[i] = tmp[i];
}

void cdq3(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq3(l, m);
    cdq3(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && aa[p].x1 < aa[q].x1) {
            if(aa[p].ty == 1) add(aa[p].y1, 1, bit);
            else if(aa[p].ty == 2) add(aa[p].y1, -1, bit);
            tmp[tp++] = aa[p];
            ++p;
        }
        if(aa[q].ty == 3) {
            aa[q].ans += sum(M-1, bit) - sum(aa[q].y1, bit);
        }
        tmp[tp++] = aa[q];
        ++q;
    }
    for (int i = l; i < p; ++i) if(aa[i].ty == 1) add(aa[i].y1, -1, bit); else if(aa[i].ty == 2) add(aa[i].y1, 1, bit);
    while(p <= m) tmp[tp++] = aa[p], ++p;
    for (int i = l; i <= r; ++i) aa[i] = tmp[i];
}

void cdq4(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq4(l, m);
    cdq4(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && aa[p].x1 > aa[q].x1) {
            if(aa[p].ty == 1) add(aa[p].y1, 1, bit);
            else if(aa[p].ty == 2) add(aa[p].y1, -1, bit);
            tmp[tp++] = aa[p];
            ++p;
        }
        if(aa[q].ty == 3) {
            aa[q].ans += sum(aa[q].y1-1, bit);
        }
        tmp[tp++] = aa[q];
        ++q;
    }
    for (int i = l; i < p; ++i) if(aa[i].ty == 1) add(aa[i].y1, -1, bit); else if(aa[i].ty == 2) add(aa[i].y1, 1, bit);
    while(p <= m) tmp[tp++] = aa[p], ++p;
    for (int i = l; i <= r; ++i) aa[i] = tmp[i];
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", op);
        if(op[0] == 'I') {
            scanf("%d %d %d %d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
            if(a[i].x1 > a[i].x2) swap(a[i].x1, a[i].x2);
            if(a[i].y1 > a[i].y2) swap(a[i].y1, a[i].y2);
            vx.pb(a[i].x1);vx.pb(a[i].x2);vy.pb(a[i].y1);vy.pb(a[i].y2);
            a[i].ty = 1;
            a[i].id = i;
            pos[++now] = i;
            ++cnt;
        }
        else if(op[0] == 'D') {
            scanf("%d", &p);
            a[i] = a[pos[p]];
            a[i].ty = 2;
            a[i].id = i;
            --cnt;
        }
        else {
            scanf("%d %d %d %d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
            if(a[i].x1 > a[i].x2) swap(a[i].x1, a[i].x2);
            if(a[i].y1 > a[i].y2) swap(a[i].y1, a[i].y2);
            vx.pb(a[i].x1);vx.pb(a[i].x2);vy.pb(a[i].y1);vy.pb(a[i].y2);
            a[i].ty = 3;
            a[i].id = i;
            a[i].cnt = a[i].ans = cnt;
        }
    }
    sort(vx.begin(), vx.end());
    vx.erase(unique(vx.begin(), vx.end()), vx.end());
    sort(vy.begin(), vy.end());
    vy.erase(unique(vy.begin(), vy.end()), vy.end());
    for (int i = 1; i <= n; ++i) {
        a[i].x1 = lower_bound(vx.begin(), vx.end(), a[i].x1) - vx.begin() + 1;
        a[i].x2 = lower_bound(vx.begin(), vx.end(), a[i].x2) - vx.begin() + 1;
        a[i].y1 = lower_bound(vy.begin(), vy.end(), a[i].y1) - vy.begin() + 1;
        a[i].y2 = lower_bound(vy.begin(), vy.end(), a[i].y2) - vy.begin() + 1;
    }
    for (int i = 1; i <= n; ++i) {
        if(a[i].ty == 1) add(a[i].x1, 1, bit1), add(a[i].x2, 1, bit2);
        else if(a[i].ty == 2) add(a[i].x1, -1, bit1), add(a[i].x2, -1, bit2);
        else a[i].ans -= sum(a[i].x1-1, bit2) + (sum(M-1, bit1) - sum(a[i].x2, bit1));
    }
    init();
    for (int i = 1; i <= n; ++i) {
        if(a[i].ty == 1) add(a[i].y1, 1, bit1), add(a[i].y2, 1, bit2);
        else if(a[i].ty == 2) add(a[i].y1, -1, bit1), add(a[i].y2, -1, bit2);
        else a[i].ans -= sum(a[i].y1-1, bit2) + (sum(M-1, bit1) - sum(a[i].y2, bit1));
    }

    for (int i = 1; i <= n; ++i) {
        aa[i] = a[i];
        if(a[i].ty <= 2) aa[i].x1 = a[i].x2, aa[i].y1 = a[i].y2;
    }
    cdq1(1, n);
    sort(aa+1, aa+1+n);
    for (int i = 1; i <= n; ++i) a[i].ans = aa[i].ans;

    for (int i = 1; i <= n; ++i) {
        aa[i] = a[i];
        if(a[i].ty == 3) aa[i].x1 = a[i].x2, aa[i].y1 = a[i].y2;
    }
    cdq2(1, n);
    sort(aa+1, aa+1+n);
    for (int i = 1; i <= n; ++i) a[i].ans = aa[i].ans;

    for (int i = 1; i <= n; ++i) {
        aa[i] = a[i];
        if(a[i].ty <= 2) aa[i].x1 = a[i].x2, aa[i].y1 = a[i].y1;
        else aa[i].x1 = a[i].x1, aa[i].y1 = a[i].y2;
    }
    cdq3(1, n);
    sort(aa+1, aa+1+n);
    for (int i = 1; i <= n; ++i) a[i].ans = aa[i].ans;

    for (int i = 1; i <= n; ++i) {
        aa[i] = a[i];
        if(a[i].ty <= 2) aa[i].x1 = a[i].x1, aa[i].y1 = a[i].y2;
        else aa[i].x1 = a[i].x2, aa[i].y1 = a[i].y1;
    }
    cdq4(1, n);
    sort(aa+1, aa+1+n);
    for (int i = 1; i <= n; ++i) a[i].ans = aa[i].ans;

    for (int i = 1; i <= n; ++i) if(a[i].ty == 3) printf("%d\n", a[i].ans);
    return 0;
}
View Code

例題4:P3157 [CQOI2011]動態逆序對 

思路:將刪除的時間當作一個維度

代碼:

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
const int N = 1e5 + 5;
struct Node {
    int t, v, pos, id;
    bool operator < (const Node & rhs) const {
        return t < rhs.t;
    }
}a[N], tmp[N];
int pos[N], ans[N], n, m, b;
LL res = 0;
struct BIT {
    int bit[N];
    void init() {
        for (int i = 1; i <= n; ++i) bit[i] = 0;
    }
    void add(int x, int a) {
        while(x <= n) bit[x] += a, x += x&-x;
    }
    int sum(int x) {
        int res = 0;
        while(x) res += bit[x], x -= x&-x;
        return res;
    }
}B;
void cdq1(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq1(l, m); cdq1(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && a[p].pos < a[q].pos) {
            B.add(a[p].v, 1);
            tmp[tp++] = a[p];
            ++p;
        }
        ans[a[q].id] += B.sum(n) - B.sum(a[q].v);
        tmp[tp++] = a[q];
        ++q;
    }      
    for (int i = l; i < p; ++i) B.add(a[i].v, -1);
    while(p <= m) tmp[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = tmp[i];
}
void cdq2(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq2(l, m); cdq2(m+1, r);
    int p = l, q = m+1, tp = l;
    while(q <= r) {
        while(p <= m && a[p].pos > a[q].pos) {
            B.add(a[p].v, 1);
            tmp[tp++] = a[p];
            ++p;
        }
        ans[a[q].id] += B.sum(a[q].v-1);
        tmp[tp++] = a[q];
        ++q;
    }      
    for (int i = l; i < p; ++i) B.add(a[i].v, -1);
    while(p <= m) tmp[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = tmp[i];
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i].v);
        a[i].pos = i;
        a[i].id = 0;
        a[i].t = 0;
        pos[a[i].v] = i;
    }
    for (int i = 1; i <= n; ++i) {
        res += B.sum(n) - B.sum(a[i].v);
        B.add(a[i].v, 1);
    }
    B.init();
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &b);
        a[pos[b]].id = i;
        a[pos[b]].t = m-i+1;
    }
    sort(a+1, a+1+n);
    cdq1(1, n);
    sort(a+1, a+1+n);
    cdq2(1, n);
    for (int i = 1; i <= m; ++i) {
        printf("%lld\n", res);
        res -= ans[i];
    }
    return 0;
}
View Code

例題5:UVALive - 6667

思路:嚴格三維偏序,在對x排序時,若是x相同,按y從大到小排序,這樣x相同是左邊區間就不會對右邊區間產生貢獻了,由於這時左邊y大於等於右邊y

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 3e5 + 10, MM = 1e6 + 5;
struct Node {
    int x, y, z, len;
}a[N];
struct BIT {
    int bit[MM];
    void clr(int x) {
        while(x < MM) bit[x] = 0, x += x&-x;
    }
    void add(int x, int a) {
        while(x < MM) bit[x] = max(bit[x], a), x += x&-x;
    }
    int mx(int x) {
        int res = 0;
        while(x) res = max(res, bit[x]), x -= x&-x;
        return res;
    }
}b;
bool cmp1(Node a, Node b) {
    if(a.x == b.x) return a.y > b.y;
    else return a.x < b.x;
}
bool cmp2(Node a, Node b) {
    return a.y < b.y;
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m);
    sort(a+l, a+m+1, cmp2);
    sort(a+m+1, a+r+1, cmp2);
    int p = l, q = m+1;
    while(q <= r) {
        while(p <= m && a[p].y < a[q].y) b.add(a[p].z, a[p].len), ++p;
        a[q].len = max(a[q].len, b.mx(a[q].z-1)+1);
        ++q;
    }
    for (int i = l; i < p; ++i) b.clr(a[i].z);
    sort(a+m+1, a+r+1, cmp1);
    cdq(m+1, r);
}
int A, B, C = ~(1<<31), M = (1<<16)-1, m, n;
int r() {
    A = 36969 * (A & M) + (A >> 16);
    B = 18000 * (B & M) + (B >> 16);
    return (C & ((A << 16) + B)) % 1000000;
}
int main() {
    while(~scanf("%d %d %d %d", &m, &n, &A, &B)) {
        if(!m && !n && !A && !B) break;
        for (int i = 1; i <= m; ++i) {
            scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
            a[i].z++;
            a[i].len = 1;
        }
        for (int i = 1; i <= n; ++i) {
            ++m;
            a[m].x = r();
            a[m].y = r();
            a[m].z = r();
            a[m].z++;
            a[m].len = 1;
        }

        sort(a+1, a+1+m, cmp1);
        cdq(1, m);
        int ans = 1;
        for (int i = 1; i <= m; ++i) ans = max(ans, a[i].len);
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

2.四維偏序

參考:http://www.cnblogs.com/candy99/p/6442434.html

cdq套cdq

假設四維爲(a, b, c, d),在進行普通的cdq分治時,咱們歸併排序使得b有序,這個時候就能夠再套一個cdq來解決(b, c, d)的三維偏序問題,可是這時不要忘記了a的做用,

咱們要求a有序時左邊[l, m]對右邊[m+1, r]的貢獻,因此在套以前給左邊[l, m]的元素打個標記來區分,而後就能夠愉快地套cdq了。時間複雜度顯然爲O(n*log(n)^3)。

而後原題找不到了,作一道稍微複雜點的,不要忘記第二個cdq是在新數組上進行,若是在原數組上進行的話,作完之後b就不是有序的了。

HDU - 5126

思路:將一個查詢用容斥拆分紅8個查詢

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 5e4 + 5;
struct Node {
    int ty, x, y, z, c, id;
    bool flag;
}a[N*8], t1[N*8], t2[N*8];
vector<int> vc;
int T, n, ty, x1, y1, z1, x2, y2, z2, tot = 0, ans[N], cnt = 0, sz;
struct BIT {
    int bit[N*8];
    void add(int x, int a) {
        while(x <= sz) bit[x] += a, x += x&-x;
    }
    int sum(int x) {
        int res = 0;
        while(x) res += bit[x], x -= x&-x;
        return res;
    }
}B;
void cdq1(int l, int r){
    if(l == r) return ;
    int m = l+r >> 1;
    cdq1(l, m); cdq1(m+1, r);
    int p = l, q = m+1, tp = l;
    Node *a = t1, *t = t2;
    while(q <= r) {
        while(p <= m && a[p].y <= a[q].y) {
            if(a[p].flag && a[p].ty == 1) B.add(a[p].z, 1);
            t[tp++] = a[p];
            ++p;
        }
        if(!a[q].flag && a[q].ty == 2) ans[a[q].id] += a[q].c*B.sum(a[q].z);
        t[tp++] = a[q];
        ++q;
    }
    for (int i = l; i < p; ++i) if(a[i].flag && a[i].ty == 1) B.add(a[i].z, -1);
    while(p <= m) t[tp++] = a[p], ++p;
    for (int i = l; i <= r; ++i) a[i] = t[i];
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m); cdq(m+1, r);
    int p = l, q = m+1, tp = l;
    Node *t = t1;
    while(q <= r) {
        while(p <= m && a[p].x <= a[q].x) t[tp] = a[p], t[tp].flag = 1, ++tp, ++p;
        t[tp] = a[q];
        t[tp].flag = 0;
        ++tp;
        ++q;
    }
    while(p <= m) t[tp] = a[p], t[tp].flag = 1, ++tp, ++p;
    for (int i = l; i <= r; ++i) a[i] = t[i];
    cdq1(l, r);
}
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        tot = cnt = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &ty);
            if(ty == 1) {
                ++tot;
                a[tot].ty = 1;
                scanf("%d %d %d", &a[tot].x, &a[tot].y, &a[tot].z);
            }
            else {
                scanf("%d %d %d %d %d %d", &x1, &y1, &z1, &x2, &y2, &z2);
                ++cnt;
                ans[cnt] = 0;
                a[++tot] = {2, x2, y2, z2, 1, cnt, 0};
                a[++tot] = {2, x1-1, y2, z2, -1, cnt, 0};
                a[++tot] = {2, x2, y1-1, z2, -1, cnt, 0};
                a[++tot] = {2, x2, y2, z1-1, -1, cnt, 0};
                a[++tot] = {2, x1-1, y1-1, z2, 1, cnt, 0};
                a[++tot] = {2, x1-1, y2, z1-1, 1, cnt, 0};
                a[++tot] = {2, x2, y1-1, z1-1, 1, cnt, 0};
                a[++tot] = {2, x1-1, y1-1, z1-1, -1, cnt, 0};
            }
        }
        vc.clear();
        for (int i = 1; i <= tot; ++i) vc.pb(a[i].z);
        sort(vc.begin(), vc.end());
        vc.erase(unique(vc.begin(), vc.end()), vc.end());
        for (int i = 1; i <= tot; ++i) a[i].z = lower_bound(vc.begin(), vc.end(), a[i].z) - vc.begin()+1;
        sz = (int)vc.size();
        cdq(1, tot);
        for (int i = 1; i <= cnt; ++i) printf("%d\n", ans[i]);
    }
    return 0;
}

 3.其餘

cdq優化dp等。

例題1:HYSBZ - 4553

思路:設mx[i]爲第i個的最大值,mn[i]爲最小值

dp[i] = max{dp[j] + 1} 其中 j < i, mx[j] <= a[i], a[j] <= mn[i]

這是個三維偏序問題,能夠用cdq維護dp的轉移,具體看代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
struct Node {
    int v, mx, mn, id, dp;
}a[N];
struct BIT {
    int bit[N];
    void clr(int x) {
        while(x < N) bit[x] = 0, x += x&-x;
    }
    void add(int x, int a) {
        while(x < N) bit[x] = max(bit[x], a), x += x&-x;
    }
    int mx(int x) {
        int res = 0;
        while(x) res = max(res, bit[x]), x -= x&-x;
        return res;
    }
}b;
bool cmp1(Node a, Node b) {
    return a.mx < b.mx;
}
bool cmp2(Node a, Node b) {
    return a.v < b.v;
}
bool cmp3(Node a, Node b) {
    return a.id < b.id;
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m);
    sort(a+l, a+m+1, cmp1);
    sort(a+m+1, a+r+1, cmp2);
    int p = l, q = m+1;
    while(q <= r) {
        while(p <= m && a[p].mx <= a[q].v) b.add(a[p].v, a[p].dp), ++p;
        a[q].dp = max(a[q].dp, b.mx(a[q].mn)+1);
        ++q;
    }
    for (int i = l; i < p; ++i) b.clr(a[i].v);
    sort(a+m+1, a+r+1, cmp3);
    cdq(m+1, r);
}
int n, m, x, y;
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i].v);
        a[i].mn = a[i].mx = a[i].v;
        a[i].id = i;
        a[i].dp = 1;
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d", &x, &y);
        a[x].mx = max(a[x].mx, y);
        a[x].mn = min(a[x].mn, y);
    }
    cdq(1, n);
    int ans = 1;
    for (int i = 1; i <= n; ++i) ans = max(ans, a[i].dp);
    printf("%d\n", ans);
    return 0;
}
View Code

例題2:HDU - 4742

思路:一樣是dp,用bit維護最大值和最大值的個樹,有點小技巧

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 10;
struct Node {
    int x, y, z, len, cnt;
}a[N];
vector<int> vc;
int T, n, sz;
struct BIT {
    pii bit[N];
    void modify(pii &a, pii b) {
        if(b.fi == a.fi) a.se += b.se;
        else if(b.fi >  a.fi) a = b;
    }
    void clr(int x) {
        while(x <= sz) bit[x] = {0, 0}, x += x&-x;
    }
    void add(int x, pii a) {
        while( x <= sz) modify(bit[x], a), x += x&-x;
    }
    pii mx(int x) {
        pii res = {0, 0};
        while(x) modify(res, bit[x]), x -= x&-x;
        return res;
    }
}b;
bool cmp1(Node a, Node b) {
    return a.x < b.x;
}
bool cmp2(Node a, Node b) {
    return a.y < b.y;
}
pii MX(pii a, pii b) {
    if(a.fi == b.fi) return {a.fi, a.se+b.se};
    else if(a.fi > b.fi) return a;
    else return b;
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(l, m);
    sort(a+l, a+m+1, cmp2);
    sort(a+m+1, a+r+1, cmp2);
    int p = l, q = m+1;
    while(q <= r) {
        while(p <= m && a[p].y <= a[q].y) b.add(a[p].z, {a[p].len, a[p].cnt}), ++p;
        pii t1 = b.mx(a[q].z);
        t1.fi++;
        pii t2 = MX({a[q].len, a[q].cnt}, t1);
        a[q].len = t2.fi, a[q].cnt = t2.se;
        ++q;
    }
    for (int i = l; i < p; ++i) b.clr(a[i].z);
    sort(a+m+1, a+r+1, cmp1);
    cdq(m+1, r);
}
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        vc.clear();
        for (int i = 1; i <= n; ++i) {
            scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
            vc.pb(a[i].z);
            a[i].len = a[i].cnt = 1;
        }
        sort(vc.begin(), vc.end());
        vc.erase(unique(vc.begin(), vc.end()), vc.end());
        for (int i = 1; i <= n; ++i) a[i].z = lower_bound(vc.begin(), vc.end(), a[i].z) - vc.begin() + 1;
        sz = (int)vc.size();
        sort(a+1, a+1+n, cmp1);
        cdq(1, n);
        pii ans = {0, 0};
        for (int i = 1; i <= n; ++i) ans = MX(ans, {a[i].len, a[i].cnt});
        printf("%d %d\n", ans.fi, ans.se);
    }
    return 0;
}
View Code

 例題3:HDU - 5324

思路:因爲要求字典序最小,因此要求dp[i]:以i爲起點的最長上升序列,cdq的話先求右邊再求左邊

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 5e4 + 5;
struct Node {
    int L, R, id;
}a[N];
vector<int> vc, res;
int sz, n, dp[N], pre[N];
struct BIT {
    pii bit[N];
    void clr(int x) {
        while(x <= sz) bit[x] = {0, 0}, x += x&-x;
    }
    void add(int x, pii a) {
        while(x <= sz) {
            if(a.fi > bit[x].fi) bit[x] = a;
            else if(a.fi == bit[x].fi && a.se < bit[x].se) bit[x] = a;
            x += x&-x;
        }
    }
    pii mx(int x) {
        pii res = {0, 0};
        while(x) {
            if(bit[x].fi > res.fi) res = bit[x];
            else if(bit[x].fi == res.fi && bit[x].se < res.se) res = bit[x];
            x -= x&-x;
        }
        return res;
    }
}b;
bool cmp1(const Node &a, const Node &b) {
    return a.id < b.id;
}
bool cmp2(const Node &a, const Node &b) {
    return a.R > b.R;
}
void cdq(int l, int r) {
    if(l == r) return ;
    int m = l+r >> 1;
    cdq(m+1, r);
    sort(a+l, a+m+1, cmp2);
    sort(a+m+1, a+r+1, cmp2);
    int p = l, q = m+1;
    while(p <= m) {
        while(q <= r && a[q].R >= a[p].R) b.add(a[q].L, {dp[a[q].id], a[q].id}), ++q;
        pii P = b.mx(a[p].L);
        if(P.fi+1 > dp[a[p].id]) {
            dp[a[p].id] = P.fi+1;
            pre[a[p].id] = P.se;
        }
        else if(P.fi+1 == dp[a[p].id] && P.se < pre[a[p].id]) pre[a[p].id] = P.se;
        ++p;
    }
    for (int i = m+1; i < q; ++i) b.clr(a[i].L);
    sort(a+l, a+m+1, cmp1);
    cdq(l, m);
}
int main() {
    while(~scanf("%d", &n)) {
        vc.clear();
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i].L), vc.pb(a[i].L);
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i].R);
        sort(vc.begin(), vc.end());
        vc.erase(unique(vc.begin(), vc.end()), vc.end());
        sz = (int)vc.size();
        for (int i = 1; i <= n; ++i) {
            a[i].id = i;
            dp[i] = 1;
            pre[i] = 0;
            a[i].L = lower_bound(vc.begin(), vc.end(), a[i].L) - vc.begin() + 1;
        }
        cdq(1, n);
        res.clear();
        int mx = 0, pe = 0;
        res.pb(0);
        for (int i = 1; i <= n; ++i) {
            if(dp[i] > mx) {
                mx = dp[i];
                pe = pre[i];
                res[0] = i;
            }
        }
        printf("%d\n", mx);
        while(pe) {
            res.pb(pe);
            pe = pre[pe];
        }
        for (int i = 0; i < mx; ++i) printf("%d%c", res[i], " \n"[i==mx-1]);
    }
    return 0;
}
View Code

 

參考:http://www.javashuo.com/article/p-nvlhcstj-mb.html

總體二分:

1.靜態區間第k大

思路:首先對於單個查詢咱們能夠二分答案求解,對於一個二分出來的mid,若是咱們能知道小於等於mid的個數,就能判斷答案是小於等於mid仍是大於mid

總體二分就是將全部查詢的二分放在一塊兒考慮,若是對於某個查詢咱們能快速知道小於等於mid的個數(能夠用樹狀數組維護,將小於等於mid的修改按位置加入),

咱們就能知道哪些查詢答案是小於等於mid,哪些查詢答案是大於mid,哪些修改只對答案小於等於mid的查詢有用,哪些修改只對答案大於mid的查詢有用

按照這個標準將全部查詢修改分紅兩部分,遞歸求解,直到二分答案的區間長度爲1。具體實現看代碼(l,r表示二分答案的區間,L,R表示查詢或修改的區間)

時間複雜度:與cdq分治相似,爲O(n*log(n)^2)

POJ - 2104

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1.1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Node {
    int ty, x, y, k, id;
}a[N], t1[N], t2[N];
int n, m, ans[N];
struct BIT {
    int bit[N];
    inline void add(int x, int a) {
        while(x < N) bit[x] += a, x += x&-x;
    }
    inline int sum(int x) {
        int res = 0;
        while(x) res += bit[x], x -= x&-x;
        return res;
    }
}b;
void solve(int l, int r, int L, int R) {
    if(l > r || L > R) return ;
    if(l == r) {
        for (int i = L; i <= R; ++i) if(a[i].ty == 2) ans[a[i].id] = l;
        return ;
    }
    int m = l+r >> 1;
    int p = 0, q = 0;
    for (int i = L; i <= R; ++i) {
        if(a[i].ty == 2){
            int cnt = b.sum(a[i].y) - b.sum(a[i].x-1);
            if(cnt >= a[i].k) t1[++p] = a[i];
            else a[i].k -= cnt, t2[++q] = a[i];
        }
        else {
            if(a[i].x <= m) b.add(a[i].id, 1), t1[++p] = a[i];
            else t2[++q] = a[i];
        }
    }
    for (int i = 1; i <= p; ++i) if(t1[i].ty == 1) b.add(t1[i].id, -1);
    for (int i = 1; i <= p; ++i) a[L+i-1] = t1[i];
    for (int i = 1; i <= q; ++i) a[L+p+i-1] = t2[i];
    solve(l, m, L, L+p-1);
    solve(m+1, r, L+p, R);
}
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i].x);
        a[i].ty = 1;
        a[i].id = i;
    }
    for (int i = n+1; i <= n+m; ++i) {
        scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].k);
        a[i].ty = 2;
        a[i].id = i-n;
    }
    solve(-INF, INF, 1, n+m);
    for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    return 0;
}

2.動態第k大

思路:在靜態第k大的基礎上將修改拆成兩個,具體看代碼

ZOJ - 2112

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Node {
    int ty, x, y, k, id;
}q[N], t1[N], t2[N];
int n, m, a[N], ans[N];
struct BIT {
    int bit[N];
    inline void add(int x, int a) {
        while(x <= n) bit[x] += a, x += x&-x;
    }
    inline int sum(int x) {
        int res = 0;
        while(x) res += bit[x], x -= x&-x;
        return res;
    }
}b;
void solve(int l, int r, int L, int R) {
    if(l > r || L > R) return ;
    if(l == r) {
        for (int i = L; i <= R; ++i) if(q[i].ty == 2) ans[q[i].id] = l;
        return ;
    }
    int m = l+r >> 1, c1 = 0, c2 = 0;
    for (int i = L; i <= R; ++i) {
        if(q[i].ty == 2) {
            int cnt = b.sum(q[i].y) - b.sum(q[i].x-1);
            if(q[i].k <= cnt) t1[++c1] = q[i];
            else q[i].k -= cnt, t2[++c2] = q[i];
        }
        else {
            if(q[i].x <= m) b.add(q[i].id, q[i].y), t1[++c1] = q[i];
            else t2[++c2] = q[i];
        }
    }
    for (int i = 1; i <= c1; ++i) if(t1[i].ty == 1) b.add(t1[i].id, -t1[i].y);
    for (int i = 1; i <= c1; ++i) q[L+i-1] = t1[i];
    for (int i = 1; i <= c2; ++i) q[L+c1+i-1] = t2[i];
    solve(l, m, L, L+c1-1);
    solve(m+1, r, L+c1, R);
}
int T, x, y, k;
char op[10];
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m);
        int tot = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            q[++tot] = {1, a[i], 1, 0, i};
        }
        for (int i = 1; i <= m; ++i) {
            scanf("%s", op);
            if(op[0] == 'Q') {
                scanf("%d %d %d", &x, &y, &k);
                q[++tot] = {2, x, y, k, i};
            }
            else {
                scanf("%d %d", &x, &y);
                q[++tot] = {1, a[x], -1, 0, x};
                q[++tot] = {1, a[x]=y, 1, 0, x};
            }
            ans[i] = -1;
        }
        solve(0, INF, 1, tot);
        for (int i = 1; i <= m; ++i) if(~ans[i]) printf("%d\n", ans[i]);
    }
    return 0;
}

例題1:HYSBZ - 3110

思路:在線段樹上進行區間加法

代碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
//#define mp make_pair
#define pb push_back
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdi pair<double, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head

const int N = 5e4 + 5;
struct Node {
    int ty, x, y, id;
    LL c;
}a[N], t1[N], t2[N];
int n, m, ans[N];
LL tree[N<<2], lazy[N<<2];
inline void push_up(int rt) {
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
inline void push_down(int rt, int len) {
    lazy[rt<<1] += lazy[rt];
    lazy[rt<<1|1] += lazy[rt];
    tree[rt<<1] += lazy[rt]*(len - (len>>1));
    tree[rt<<1|1] += lazy[rt]*(len>>1);
    lazy[rt] = 0;
}
void update(int L, int R, int x, int rt, int l, int r) {
    if(L <= l && r <= R) {
        lazy[rt] += x;
        tree[rt] += x*(r-l+1);
        return ;
    }
    if(lazy[rt]) push_down(rt, r-l+1);
    int m = l+r >> 1;
    if(L <= m) update(L, R, x, ls);
    if(R > m) update(L, R, x, rs);
    push_up(rt);
}
LL query(int L, int R, int rt, int l, int r) {
    if(L <= l && r <= R) return tree[rt];
    if(lazy[rt]) push_down(rt, r-l+1);
    int m = l+r >> 1;
    LL ans = 0;
    if(L <= m) ans += query(L, R, ls);
    if(R > m) ans += query(L, R, rs);
    push_up(rt);
    return ans;
}
void solve(int l, int r, int L, int R) {
    if(l > r || L > R) return ;
    if(l == r) {
        for (int i = L; i <= R; ++i) if(a[i].ty == 2) ans[a[i].id] = l;
        return ;
    }
    int m = l+r >> 1, p = 0, q = 0;
    for (int i = L; i <= R; ++i) {
        if(a[i].ty == 2) {
            LL cnt = query(a[i].x, a[i].y, 1, 1, n);
            if(cnt >= a[i].c) t2[++q] = a[i];
            else a[i].c -= cnt, t1[++p] = a[i];
        }
        else {
            if(a[i].c > m) update(a[i].x, a[i].y, 1, 1, 1, n), t2[++q] = a[i];
            else t1[++p] = a[i];
        }
    }
    for (int i = 1; i <= q; ++i) if(t2[i].ty == 1) update(t2[i].x, t2[i].y, -1, 1, 1, n);
    for (int i = 1; i <= p; ++i) a[L+i-1] = t1[i];
    for (int i = 1; i <= q; ++i) a[L+p+i-1] = t2[i];
    solve(l, m, L, L+p-1);
    solve(m+1, r, L+p, R);
}
int tot = 0;
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; ++i) scanf("%d %d %d %lld", &a[i].ty, &a[i].x, &a[i].y, &a[i].c), a[i].id = (a[i].ty == 1)?i:(++tot);
    solve(-n, n, 1, m);
    for (int i = 1; i <= tot; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

例題2:P1527 [國家集訓隊]矩陣乘法 

思路:在二維樹狀數組上進行加法

代碼:

#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define LL long long 

const int N = 505, M = 3.2e5 + 5;
const int INF = 0x3f3f3f3f;
struct Node {
    int ty, x1, y1, x2, y2, k, id;
}a[M], t1[M], t2[M];
int n, m, ans[M];
struct BIT2 {
    int bit[N][N];
    inline void add(int x, int y, int a) {
        for (int i = x; i <= n; i += i&-i) {
            for (int j = y; j <= n; j += j&-j) {
                bit[i][j] += a;
            }
        }
    }
    inline int sum(int x, int y) {
        int res = 0;
        for (int i = x; i > 0; i -= i&-i) {
            for (int j = y; j > 0; j -= j&-j) {
                res += bit[i][j];
            }
        }
        return res;
    }
}B;
void solve(int l, int r, int L, int R){
    if(l > r || L > R) return ;
    if(l == r) {
        for (int i = L; i <= R; ++i) {
            if(a[i].ty == 2) ans[a[i].id] = l;
        }
        return ;
    }
    int m = l+r >> 1, p = 0, q = 0;
    for (int i = L; i <= R; ++i) {
        if(a[i].ty == 1) {
            if(a[i].k <= m) B.add(a[i].x1, a[i].y1, 1), t1[++p] = a[i];
            else t2[++q] = a[i];
        }
        else {
            int cnt = B.sum(a[i].x2, a[i].y2) - B.sum(a[i].x1-1, a[i].y2) - B.sum(a[i].x2, a[i].y1-1) + B.sum(a[i].x1-1, a[i].y1-1);
            if(cnt >= a[i].k) t1[++p] = a[i];
            else a[i].k -= cnt, t2[++q] = a[i];
        }
    }
    for (int i = 1; i <= p; ++i) if(t1[i].ty == 1) B.add(t1[i].x1, t1[i].y1, -1);
    for (int i = 1; i <= p; ++i) a[L+i-1] = t1[i];
    for (int i = 1; i <= q; ++i) a[L+p+i-1] = t2[i];
    solve(l, m, L, L+p-1);
    solve(m+1, r, L+p, R);
}
int main() {
    int tot = 0;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            ++tot;
            scanf("%d", &a[tot].k);
            a[tot].x1 = i;
            a[tot].y1 = j;
            a[tot].ty = 1;
        }
    }
    for (int i = 1; i <= m; ++i) {
        ++tot;
        scanf("%d %d %d %d %d", &a[tot].x1, &a[tot].y1, &a[tot].x2, &a[tot].y2, &a[tot].k);
        a[tot].ty = 2;
        a[tot].id = i;
    }
    solve(-INF, INF, 1, tot);
    for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code
相關文章
相關標籤/搜索