CDQ分治&整体二分学习个人小结

目录

  • 小结
  • CDQ分治
    • 二维LIS
    • 第一道裸题 bzoj1176 Mokia
    • bzoj3262 陌上花开
    • bzoj 1790 矩形藏宝地
    • hdu5126四维偏序
    • P3157 [CQOI2011]动态逆序对
    • CF 762E
    • CSUSTOJ 1024:CDQ
    • CSUSTOJ 1026:强制在线树套树
  • 整体二分
    • 动态区间第k小
    • P3332 [ZJOI2013]K大数查询

初学推荐博客:LemonMZc BraketBN Owen_codeisking
CDQ&整体二分教程和题目:Winniechen
1

小结

CDQ分治

二维LIS

如果你还没学过CDQ分治,可以先忽略这题。。。呃

  • 首先这题一看就是一个三维偏序的裸题,不过普通CDQ分治的写法会wa,因为求LIS是有后效性的。
  • 我们不能先解决左边,再解决右边,最后合并,
  • 比如:定义\(dp[i]\)表示以\(i\)结尾的元素的LIS的长度。
  • 但是他只能记录末位置,而不知道从哪些地方转移来。
  • 如果在一次合并前就解决了子区间\([mid+1,r]\)区间内的情况,这次合并就算重复的贡献。
  • 因此,我们需要先解决左边,向右边转移后,再解决右边。

AC_Code

const int MXN = 1e5 + 7;
const int MXE = 1e6 + 7;
int n, m;
pii ar[MXN];
struct lp {
    int fi, se, val, id;
}cw[MXN];
int ans;
bool cmp(const lp&a, const lp&b) {
    return a.se < b.se;
}
bool cmp2(const lp&a, const lp&b) {
    return a.id < b.id;
}
int bit[MXN];
int N;
void bit_add(int x, int v) {
    while(x <= N) {
        bit[x] = big(bit[x], v);
        x += lowbit(x);
    }
}
void bit_clr(int x) {
    while(x <= N) {
        bit[x] = 0;
        x += lowbit(x);
    }
}
int bit_query(int x) {
    int ans = 0;
    while (x > 0) {
        ans = big(ans, bit[x]);
        x -= lowbit(x);
    }
    return ans;
}
void solve(int l, int r) {
    if(l >= r) return;
    int mid = (l + r) >> 1;
    solve(l, mid);
    sort(cw + l, cw + mid + 1, cmp);
    sort(cw + mid + 1, cw + r + 1, cmp);
    int i = l;
    for(int j = mid + 1; j <= r; ++j) {
        for(; i <= mid && cw[i].se < cw[j].se; ++i) bit_add(cw[i].fi, cw[i].val);
        cw[j].val = big(cw[j].val, bit_query(cw[j].fi - 1) + 1);
    }
    for(-- i; i >= l; --i) bit_clr(cw[i].fi);
//    inplace_merge(cw + l, cw + mid + 1, cw + r + 1, cmp);
    sort(cw + mid + 1, cw + r + 1, cmp2);
    solve(mid + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
//    int tim = 1;
    n = read();
    vector vs;
    for(int i = 1; i <= n; ++i) {
        ar[i].fi = read(), ar[i].se = read();
        vs.eb(ar[i].fi);
    }
    my_unique(vs);
    for(int i = 1; i <= n; ++i) {
        ar[i].fi = lower_bound(all(vs), ar[i].fi) - vs.begin() + 1;
        cw[i].fi = ar[i].fi, cw[i].se = ar[i].se, cw[i].val = 1, cw[i].id = i;
    }
    N = vs.size() + 1;
    ans = 1;
    solve(1, n);
    for(int i = 1; i <= n; ++i) ans = big(ans, cw[i].val);
    printf("%d\n", ans);
    return 0;
}

第一道裸题 bzoj1176 Mokia

/*
2000000的矩阵,单点更新,区间查询
一维时间,一维x,树状数组维护y
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;
 
const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;
 
 
int n, k, s, cnt;
LL ans[MXN];
struct lp {
    int x, y, ip, idx, delta;
}cw[MXN];
bool cmp(const lp &a, const lp &b) {
    return a.x < b.x ||(a.x == b.x && a.y < b.y);
}
LL bit[MXN];
int lowbit(int x){return (x&(-x));}
void add(int x,int c){for(;x <= n;x += lowbit(x)) bit[x]+=c;}
LL query(int x){LL ans = 0;for(;x;x -= lowbit(x))ans+=bit[x];return ans;}
void cdq(int l, int r) {
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid+1,r);
    int j = l;
    for(int i = mid+1; i <= r; ++i) {
        if(cw[i].ip == 2) {
            for(; j <= mid && cw[j].x <= cw[i].x; ++j) {
                if(cw[j].ip == 1) add(cw[j].y, cw[j].delta);
            }
            ans[cw[i].idx] += cw[i].delta * query(cw[i].y);
        }
    }
    for(-- j; j >= l; --j) if(cw[j].ip == 1) add(cw[j].y, -cw[j].delta);
    inplace_merge(cw+l,cw+mid+1,cw+r+1, cmp);
}
int main() {
    scanf("%d%d", &s, &n);
    cnt = 0;
    int cntp = 0, x, y, a, b;
    while(scanf("%d", &k) == 1 && k != 3) {
        if(k == 1) {
            scanf("%d%d%d", &x, &y, &a);
            ++ cnt;
            cw[cnt] = {x, y, 1, cnt, a};
        }else {
            scanf("%d%d%d%d", &x, &y, &a, &b);
            ++ cntp; ans[cntp] = (1LL*a - x)*(b - y)*s;
            ++ cnt; cw[cnt] = {x-1, y-1, 2, cntp, 1};
            ++ cnt; cw[cnt] = {x-1, b, 2, cntp, -1};
            ++ cnt; cw[cnt] = {a, y-1, 2, cntp, -1};
            ++ cnt; cw[cnt] = {a, b, 2, cntp, 1};
        }
    }
    cdq(1, cnt);
    for(int i = 1; i <= cntp; ++i) printf("%lld\n", ans[i]);
    return 0;
}

bzoj3262 陌上花开

/*
简单地说,对于每个点求出x,y,z都小于等于它的点的个数
一维x,一维y,树状数组维护z
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;

int n, s;
struct lp {
    int x, y, z, ip, cnt, ans;
}cw[MXN], temp[MXN];
bool cmpx(const lp &a, const lp &b) {
    return a.x < b.x ||(a.x == b.x && a.y < b.y)||(a.x == b.x && a.y == b.y && a.z < b.z);
}
bool cmpyz(const lp &a, const lp &b) {
    return a.y < b.y||(a.y == b.y && a.z < b.z);
}
int bit[MXN];
int lowbit(int x){return (x&(-x));}
void add(int x,int c){for(;x <= s;x += lowbit(x)) bit[x]+=c;}
int query(int x){int ans = 0;for(;x;x -= lowbit(x))ans+=bit[x];return ans;}
void cdq(int l,int r) {
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid+1, r);
    //sort(cw + l, cw + 1 + mid, cmpyz);   
    //sort(cw + 1 + mid, cw + 1 + r, cmpyz);
    int j = l;
    for(int i = mid+1; i <= r; ++i) {
        for(; j <= mid && cw[j].y <= cw[i].y; ++j) {
            add(cw[j].z, cw[j].cnt);
        }
        cw[i].ans += query(cw[i].z);
    }
    for(-- j; j >= l; --j) add(cw[j].z, -cw[j].cnt);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(p1 <= mid && cw[p1].y <= cw[p2].y) temp[cnt++] = cw[p1], ++ p1;
        else temp[cnt++] = cw[p2], ++ p2;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++ p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
int main() {
    scanf("%d%d", &n, &s);
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d%d", &cw[i].x, &cw[i].y, &cw[i].z);
        cw[i].ip = i; cw[i].ans = 0;
    }
    sort(cw + 1, cw + 1 + n, cmpx);
    int cnt = 1, p = 0;
    for(int i = 2; i <= n; ++i) {
        if(cw[i].x!=cw[i-1].x||cw[i].y!=cw[i-1].y||cw[i].z!=cw[i-1].z) {
            cw[++p] = cw[i-1];
            cw[p].cnt = cnt;
            cnt = 1;
            if(i == n) {
                cw[++p] = cw[i];
                cw[p].cnt = cnt;
            }
        }else {
            ++ cnt;
            if(i == n) {
                cw[++p] = cw[i-1];
                cw[p].cnt = cnt;
            }
        }
    }
    cdq(1, p);
    for(int i = 1; i <= p; ++i) bit[cw[i].ans+cw[i].cnt-1] += cw[i].cnt;
    for(int i = 0; i < n; ++i) printf("%d\n", bit[i]);
    return 0;
}

bzoj 1790 矩形藏宝地

/*
对每个点询问是否存在一个点a,b小于等于它,c,d大于等于它
一维c,一维d,离散化a,线段树维护a上的b
*/
#include
using namespace std;
typedef long long LL;

const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 6;

int n, m, k, ans;
struct lp {
    int a, b, c, d, ans;
}cw[MXN], temp[MXN];
int ar[MXN], sum[MXN<<2];
bool cmpc(const lp &A, const lp &B) {
    return A.c > B.c;
}
bool cmpd(const lp &A, const lp &B) {
    return A.d > B.d;
}
void update(int p,int val,int l,int r,int rt) {
    if(l == r) {
        sum[rt] = val;
        return ;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) update(p, val, l, mid, rt<<1);
    else update(p, val, mid+1, r, rt<<1|1);
    sum[rt] = min(sum[rt<<1], sum[rt<<1|1]);
}
int query(int L,int R,int l,int r,int rt) {
    if(L <= l && r <= R) {
        return sum[rt];
    }
    int mid = (l + r) >> 1;
    if(L > mid) return query(L,R,mid+1,r,rt<<1|1);
    else if(R <= mid) return query(L,R,l,mid,rt<<1);
    else {
        return min(query(L,mid,l,mid,rt<<1),
            query(mid+1,R,mid+1,r,rt<<1|1));
    }
}
void cdq(int l,int r) {
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid+1, r);
    int j = l;
    for(int i = mid+1; i <= r; ++i) {
        for(; j <= mid && cw[j].d >= cw[i].d; ++j) {
            update(cw[j].a, cw[j].b, 1, k, 1);
        }
        if(query(1,cw[i].a,1,k,1) <= cw[i].b) cw[i].ans = 1;
    }
    for(-- j; j >= l; --j) update(cw[j].a, INF, 1, k, 1);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(p1 <= mid && cw[p1].d >= cw[p2].d) temp[cnt++] = cw[p1], ++ p1;
        else temp[cnt++] = cw[p2], ++ p2;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++ p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d%d%d", &cw[i].a, &cw[i].b, &cw[i].c, &cw[i].d);
        ar[i] = cw[i].a; cw[i].ans = 0;
    }
    memset(sum, 0x3f, sizeof(sum));
    sort(ar+1, ar+1+n);
    k = unique(ar+1,ar+1+n) - ar;
    sort(cw + 1, cw + 1 + n, cmpc);
    for(int i = 1; i <= n; ++i) {
        cw[i].a = lower_bound(ar+1,ar+k,cw[i].a) - ar;
        cw[i].c = i;
    }
    cdq(1, n);
    for(int i = 1; i <= n; ++i) ans += cw[i].ans;
    printf("%d\n", ans);
    return 0;
}

hdu5126四维偏序

/*
三维空间n次操作,更新一个点,查询两点的长方体间点的个数
CDQ套CDQ:一维时间,一维x,再一维y,树状数组维护z
每次查询,三维容斥一下,分成8个区间的查询
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 2e6 + 6;
const int INF = 0x3f3f3f3f;

int n, tot, k;
struct lp {
    int x, y, z, flag, idx, ip, delta;
}cw[MXN], temp[MXN], Tmp[MXN];
int ans[MXN], ar[MXN];
int bit[MXN];
int lowbit(int x){return (x&(-x));}
void add(int x,int c){for(;x <= 400006;x += lowbit(x)) bit[x]+=c;}
int query(int x){int ANs = 0;for(;x;x -= lowbit(x))ANs+=bit[x];return ANs;}
void cdq2(int l,int r) {
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq2(l, mid); cdq2(mid+1, r);
    int j = l;
    for(int i = mid+1; i <= r; ++i) {
        for(; j <= mid && temp[j].y <= temp[i].y; ++j)
            if(temp[j].ip == 1&&temp[j].flag == 0) add(temp[j].z, 1);
        if(temp[i].ip == 2&&temp[i].flag == 1) {
            ans[temp[i].idx] += query(temp[i].z)*temp[i].delta;
        }
    }
    for(-- j; j >= l; --j) if(temp[j].ip == 1&&temp[j].flag == 0) add(temp[j].z, -1);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(temp[p1].y <= temp[p2].y) {
            Tmp[cnt++] = temp[p1]; ++ p1;
        }else {
            Tmp[cnt++] = temp[p2]; ++ p2;
        }
    }
    while(p1 <= mid) {
        Tmp[cnt++] = temp[p1]; ++ p1;
    }
    while(p2 <= r) {
        Tmp[cnt++] = temp[p2]; ++ p2;
    }
    for(int i = l; i <= r; ++i) temp[i] = Tmp[i];
}
void cdq1(int l,int r) {
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq1(l, mid); cdq1(mid+1, r);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(cw[p1].x <= cw[p2].x) {
            temp[cnt++] = cw[p1]; ++ p1;
            temp[cnt-1].flag = 0;
        }else {
            temp[cnt++] = cw[p2]; ++ p2;
            temp[cnt-1].flag = 1;
        }
    }
    while(p1 <= mid) {
        temp[cnt++] = cw[p1]; ++ p1;
        temp[cnt-1].flag = 0;
    }
    while(p2 <= r) {
        temp[cnt++] = cw[p2]; ++ p2;
        temp[cnt-1].flag = 1;
    }
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
    cdq2(l, r);
}
int main() {
    int tim; scanf("%d", &tim);
    while(tim --) {
        scanf("%d", &n);
        tot = 0;
        int totp = 0;
        for(int i = 0; i < n; ++i) {
            int opt, x1, y1, z1, x2, y2, z2;
            scanf("%d%d%d%d", &opt, &x1, &y1, &z1);
            if(opt == 1) {
                ++ tot; cw[tot] = {x1, y1, z1, 0, 0, 1, 0};
            }else {
                scanf("%d%d%d", &x2, &y2, &z2);
                ++ totp;
                ++ tot; cw[tot] = {x2, y2, z2, 0, totp, 2, 1};
                ++ tot; cw[tot] = {x1-1, y2, z2, 0, totp, 2, -1};
                ++ tot; cw[tot] = {x2, y1-1, z2, 0, totp, 2, -1};
                ++ tot; cw[tot] = {x2, y2, z1-1, 0, totp, 2, -1};
                ++ tot; cw[tot] = {x1-1, y1-1, z2, 0, totp, 2, 1};
                ++ tot; cw[tot] = {x1-1, y2, z1-1, 0, totp, 2, 1};
                ++ tot; cw[tot] = {x2, y1-1, z1-1, 0, totp, 2, 1};
                ++ tot; cw[tot] = {x1-1, y1-1, z1-1, 0, totp, 2, -1};
            }
        }
        for(int i = 1; i <= tot; ++i) ar[i] = cw[i].z;
        sort(ar+1, ar+1+tot);
        k = unique(ar+1, ar+1+tot) - ar;
        for(int i = 1; i <= tot; ++i) cw[i].z = lower_bound(ar+1, ar+k, cw[i].z)-ar;
        cdq1(1, tot);
        for(int i = 1; i <= totp; ++i) printf("%d\n", ans[i]), ans[i] = 0;
    }
    return 0;
}

P3157 [CQOI2011]动态逆序对

CDQ

/*
给1到n的一个排列,按某顺序依次删除m个元素,求在每次删除一个元素之前序列的逆序对数。
*/
//对不起,我太暴力了
#include
using namespace std;
typedef long long LL;

const int MXN = 1e5 + 6;
const int INF = 0x3f3f3f3f;

int n, m;
LL tot;
struct lp {
    int x, tim, pos;
    LL ans;
}cw[MXN], temp[MXN], Tmp[MXN];
LL ans[MXN], ar[MXN];
LL bit[MXN];
int lowbit(int x){return (x&(-x));}
void ADD(int x,int c){for(; x <= n; x += lowbit(x)) bit[x]+=c;}
LL QUERY(int x){LL ANS = 0;for(; x; x -= lowbit(x)) ANS+=bit[x];return ANS;}
bool cmppos(const lp &a, const lp &b) {
    return a.pos > b.pos;
}
void cdq1(int l,int r) {//求出每个数左边有多少个时间比你大的且值比你大的数
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq1(l, mid); cdq1(mid+1, r);
    int j = l;
    for(int i = mid + 1; i <= r; ++i) {
        for(; j <= mid && cw[j].tim >= cw[i].tim; ++j) {
            if(cw[j].tim) ADD(cw[j].x, 1);
        }
        cw[i].ans += QUERY(n) - QUERY(cw[i].x);
    }
    for(-- j; j >= l; --j) if(cw[j].tim) ADD(cw[j].x, -1);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(cw[p1].tim >= cw[p2].tim) temp[cnt++] = cw[p1], ++p1;
        else temp[cnt++] = cw[p2], ++ p2;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
void cdq2(int l,int r) {//求出每个数右边有多少个时间比你大的且值比你小的数
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq2(l, mid); cdq2(mid+1, r);
    int j = l;
    for(int i = mid + 1; i <= r; ++i) {
        for(; j <= mid && cw[j].tim >= cw[i].tim; ++j) {
            if(cw[j].tim) ADD(cw[j].x, 1);
        }
        cw[i].ans += QUERY(cw[i].x);
    }
    for(-- j; j >= l; --j) if(cw[j].tim) ADD(cw[j].x, -1);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(cw[p1].tim >= cw[p2].tim) temp[cnt++] = cw[p1], ++p1;
        else temp[cnt++] = cw[p2], ++ p2;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
void cdq(int l,int r) {
    if(l == r) return ;
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid+1, r);
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(cw[p1].x <= cw[p2].x) temp[cnt++] = cw[p1], ++p1;
        else temp[cnt++] = cw[p2], ++ p2, tot += mid-p1+1;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &cw[i].x);
        cw[i].tim = 0;
        cw[i].ans = 0;
        ar[cw[i].x] = i;
        cw[i].pos = i;
    }
    for(int i = 1, x; i <= m; ++i) {
        scanf("%d", &x);
        cw[ar[x]].tim = i;
    }
    cdq(1, n);
    sort(cw + 1, cw + 1 + n, cmppos);
    reverse(cw + 1, cw + 1 + n);
    for(int i = 1; i <= n; ++i) {
        if(cw[i].tim == 0) {
            ADD(cw[i].x, 1);
        }else {
            ans[cw[i].tim] += QUERY(n) - QUERY(cw[i].x);
        }
    }
    memset(bit, 0, sizeof(LL)*(n+10));
    for(int i = n; i >= 1; --i) {
        if(cw[i].tim == 0) {
            ADD(cw[i].x, 1);
        }else {
            ans[cw[i].tim] += QUERY(cw[i].x);
        }
    }
    memset(bit, 0, sizeof(LL)*(n+10));
    cdq1(1, n);
    for(int i = 1; i <= n; ++i) {
        ans[cw[i].tim] += cw[i].ans;
        cw[i].ans = 0;
    }
    sort(cw + 1, cw + 1 + n, cmppos);
    cdq2(1, n);
    for(int i = 1; i <= n; ++i) {
        ans[cw[i].tim] += cw[i].ans;
    }
    printf("%lld\n", tot);
    for(int i = 1; i < m; ++i) {
        tot -= ans[i];
        printf("%lld\n", tot);
    }
    return 0;
}

树套树

/*
树状数组套权值线段树
这东西是干什么的呢?
个人感觉大概就是把那种O(n)*O(1)的复杂度优化成O(log)*O(log)的复杂度
比如n个位置,每个位置一个值,查询是O(1)的;log个位置(树状数组),查询是O(log)的(权值线段树/主席树)
本题把每次询问拆分成两个前缀和相减,然后用树套树优化,树状数组每个节点维护的范围不变,然后将节点变成权值线段树,就是本题的做法。
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 2e5 + 6;
const int MXE = 6e6 + 6;
const int INF = 0x3f3f3f3f;

int n, m;
struct lp {
    int l, r;
    LL sum;
}cw[MXE], temp[MXN], Tmp[MXN];
int lb[MXN], rs[MXN], ar[MXN], bel[MXN];
int Root[MXN], NODE, A[MXE], B[MXE];
LL bit[MXN];
int lowbit(int x){return (x&(-x));}
void ADD(int x,int c){for(; x <= n; x += lowbit(x)) bit[x]+=c;}
LL QUERY(int x){LL ANS = 0;for(; x; x -= lowbit(x)) ANS+=bit[x];return ANS;}

bool cmppos(const lp &a, const lp &b) {
    return a.sum > b.sum;
}
void update(int &cur, int x, int l, int r) {
    if(!cur) {
        cur = ++ NODE;
        cw[cur].l = cw[cur].r = 0;
    }
    ++ cw[cur].sum;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(x <= mid) update(cw[cur].l, x, l, mid);
    else update(cw[cur].r, x, mid+1, r);
}
LL Find(int l,int r,int lw,int up,int rt) {
    if(lw <= l && r <= up) {
        return cw[rt].sum;
    }
    if(lw > r || up < l) return 0;
    int mid = (l + r) >> 1;
    if(lw > mid) return Find(mid+1, r, lw, up, cw[rt].r);
    else if(up <= mid) return Find(l, mid, lw, up, cw[rt].l);
    return Find(l, mid, lw, mid, cw[rt].l)+Find(mid+1,r,mid+1,up,cw[rt].r);
}
LL query(int l,int r,int lw,int up) {
    if(lw > up) return 0;
    if(l >= r) return 0;
    A[0] = B[0] = 0;
    for(; r; r -= lowbit(r)) A[++A[0]] = Root[r];//树状数组的求和,每个节点都是一个权值线段树,每个节点的查询时O(log)的
    for(; l; l -= lowbit(l)) B[++B[0]] = Root[l];
    LL ans = 0;
    for(int i = 1; i <= A[0]; ++i) ans += Find(1,n,lw,up,A[i]);
    for(int i = 1; i <= B[0]; ++i) ans -= Find(1,n,lw,up,B[i]);
    return ans;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &ar[i]);
        bel[ar[i]] = i;
    }
    LL tot = 0;
    for(int i = 1; i <= n; ++i) {
        lb[i] = QUERY(n) - QUERY(ar[i]);
        ADD(ar[i], 1);
        tot += lb[i];
        cw[i].l = cw[i].r = 0;
    }
    memset(bit, 0, sizeof(LL)*(n+5));
    for(int i = n; i >= 1; --i) {
        rs[i] = QUERY(ar[i]-1);
        ADD(ar[i], 1);
    }
    memset(bit, 0, sizeof(LL)*(n+5));
    printf("%lld\n", tot);
    NODE = n;
    for(int i = 1, x; i < m; ++i) {
        scanf("%d", &x);
        tot -= (lb[bel[x]] + rs[bel[x]] - query(0,bel[x]-1,x+1,n) - query(bel[x],n,1,x-1));
        printf("%lld\n", tot);
        for(int y = bel[x]; y <= n; y += lowbit(y)) {//将所有包含bel[x]位置的权值线段树更新
            update(Root[y], x, 1, n);
        }
    }
    scanf("%d", &m);
    return 0;
}
//这样写跑的快一点
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 2e5 + 6;
const int MXE = 6e6 + 6;
const int INF = 0x3f3f3f3f;

int n, m;
struct lp {
    int l, r;
    LL sum;
}cw[MXE], temp[MXN], Tmp[MXN];
int lb[MXN], rs[MXN], ar[MXN], bel[MXN];
int Root[MXN], NODE, A[MXE], B[MXE];
LL bit[MXN];
int lowbit(int x){return (x&(-x));}
void ADD(int x,int c){for(; x <= n; x += lowbit(x)) bit[x]+=c;}
LL QUERY(int x){LL ANS = 0;for(; x; x -= lowbit(x)) ANS+=bit[x];return ANS;}

bool cmppos(const lp &a, const lp &b) {
    return a.sum > b.sum;
}
void update(int &cur, int x, int l, int r) {
    if(!cur) {
        cur = ++ NODE;
        cw[cur].l = cw[cur].r = 0;
    }
    ++ cw[cur].sum;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(x <= mid) update(cw[cur].l, x, l, mid);
    else update(cw[cur].r, x, mid+1, r);
}
LL queryda(int l,int r,int x) {
    if(l >= r) return 0;
    A[0] = B[0] = 0;
    for(; r; r -= lowbit(r)) A[++A[0]] = Root[r]; 
    for(; l; l -= lowbit(l)) B[++B[0]] = Root[l];
    LL ans = 0;
    l = 1, r = n;
    int mid;
    while(l + 1 <= r) {
        mid = (l + r) >> 1;
        if(x <= mid) {
            for(int i = 1; i <= A[0]; ++i) ans += cw[cw[A[i]].r].sum;
            for(int i = 1; i <= B[0]; ++i) ans -= cw[cw[B[i]].r].sum;
            for(int i = 1; i <= A[0]; ++i) A[i] = cw[A[i]].l;
            for(int i = 1; i <= B[0]; ++i) B[i] = cw[B[i]].l;
            r = mid;
        }else {
            for(int i = 1; i <= A[0]; ++i) A[i] = cw[A[i]].r;
            for(int i = 1; i <= B[0]; ++i) B[i] = cw[B[i]].r;
            l = mid + 1;
        }
    }
    return ans;
}
LL queryxiao(int l,int r,int x) {
    if(l >= r) return 0;
    A[0] = B[0] = 0;
    for(; r; r -= lowbit(r)) A[++A[0]] = Root[r]; 
    for(; l; l -= lowbit(l)) B[++B[0]] = Root[l];
    LL ans = 0;
    l = 1, r = n;
    int mid;
    x - 1;
    while(l + 1 <= r) {
        mid = (l + r) >> 1;
        if(x >= mid + 1) {
            for(int i = 1; i <= A[0]; ++i) ans += cw[cw[A[i]].l].sum;
            for(int i = 1; i <= B[0]; ++i) ans -= cw[cw[B[i]].l].sum;
            for(int i = 1; i <= A[0]; ++i) A[i] = cw[A[i]].r;
            for(int i = 1; i <= B[0]; ++i) B[i] = cw[B[i]].r;
            l = mid + 1;
        }else {
            for(int i = 1; i <= A[0]; ++i) A[i] = cw[A[i]].l;
            for(int i = 1; i <= B[0]; ++i) B[i] = cw[B[i]].l;
            r = mid;
        }
    }
    return ans;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &ar[i]);
        bel[ar[i]] = i;
    }
    LL tot = 0;
    for(int i = 1; i <= n; ++i) {
        lb[i] = QUERY(n) - QUERY(ar[i]);
        ADD(ar[i], 1);
        tot += lb[i];
        cw[i].l = cw[i].r = 0;
    }
    memset(bit, 0, sizeof(LL)*(n+5));
    for(int i = n; i >= 1; --i) {
        rs[i] = QUERY(ar[i]-1);
        ADD(ar[i], 1);
    }
    memset(bit, 0, sizeof(LL)*(n+5));
    printf("%lld\n", tot);
    NODE = n;
    for(int i = 1, x; i < m; ++i) {
        scanf("%d", &x);
        tot -= (lb[bel[x]]+rs[bel[x]]-queryda(0,bel[x]-1,x)-queryxiao(bel[x],n,x));
        printf("%lld\n", tot);
        for(int y = bel[x]; y <= n; y += lowbit(y)) {
            update(Root[y], x, 1, n);
        }
    }
    scanf("%d", &m);
    return 0;
}

bzoj1176 树套树但是我过不了

我不会平衡树昂,就不能让我套个线段树吗?你疯狂给我mle&re是个啥意思?难度要去学平衡树吗?。。不,我不学。。。难受啊

#include
using namespace std;
typedef long long LL;
const int MXN = 2e5 + 5;
const int MXE = 1e7 + 3e6 + 6;
const int INF = 0x3f3f3f3f;
int n, m;
int s, p, k;
int Root[MXN], NODE;
int ar[MXN], br[MXN];
struct lp {
    int x, y, X, Y, idx;
}cw[MXN];
struct tree {
    int l, r, sum;
}edge[MXE];
int lowbit(int x){return (x&(-x));}
void update(int &p, int pos, int x, int l, int r) {
    if(!p) {
        p = ++ NODE;
        edge[p].l = edge[p].r = edge[p].sum = 0;
    }
    edge[p].sum += x;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(pos <= mid) update(edge[p].l, pos, x, l, mid);
    else update(edge[p].r, pos, x, mid+1, r);
}
int query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return edge[rt].sum;
    }
    if(L > r || R < l) return 0;
    int mid = (l + r) >> 1;
    if(L > mid) return query(L, R, mid + 1, r, edge[rt].r);
    else if(R <= mid) return query(L, R, l, mid, edge[rt].l);
    return query(L,mid,l,mid,edge[rt].l)+query(mid+1,R,mid+1,r,edge[rt].r);
}
int CALC(int X, int Y) {
    int ans = 0;
    if(X == 0 || Y == 0) return ans;
    for(int u = X; u; u -= lowbit(u)) {
        ans += query(1, Y, 1, p, Root[u]);
    }
    return ans;
}
int main() {
    scanf("%d%d", &s, &m);
    int tot;
    for(int i = 1;; ++ i) {
        tot = i;
        scanf("%d", &cw[i].idx);
        if(cw[i].idx == 1) {
            scanf("%d%d", &cw[i].x, &cw[i].y);
            scanf("%d", &cw[i].X);
        }else if(cw[i].idx == 2) {
            scanf("%d%d", &cw[i].x, &cw[i].y);
            scanf("%d%d", &cw[i].X, &cw[i].Y);
        }else break;
    }
    -- tot;
    k = 0, p = 0;
    for(int i = 1; i <= tot; ++i) {
        ar[++ k] = cw[i].x;
        if(cw[i].idx == 2) ar[++ k] = cw[i].X;
        br[++ p] = cw[i].y;
        if(cw[i].idx == 2) br[++ p] = cw[i].Y;
    }
    sort(ar + 1, ar + k + 1);
    sort(br + 1, br + p + 1);
    k = unique(ar + 1, ar + k + 1) - ar;
    p = unique(br + 1, br + p + 1) - br;
    NODE = p-1;
    for(int i = 1; i <= tot; ++i) {
        cw[i].x = lower_bound(ar + 1, ar + k, cw[i].x)-ar;
        cw[i].y = lower_bound(br + 1, br + p, cw[i].y)-br;
        if(cw[i].idx == 1) {
            for(int y = cw[i].x; y <= k; y += lowbit(y)) {
                update(Root[y], cw[i].y, cw[i].X, 1, p);
            }
        }else {
            cw[i].X = lower_bound(ar + 1, ar + k, cw[i].X)-ar;
            cw[i].Y = lower_bound(br + 1, br + p, cw[i].Y)-br;
            printf("%d\n", CALC(cw[i].X, cw[i].Y)-CALC(cw[i].X,cw[i].y-1)
                -CALC(cw[i].x-1,cw[i].Y)+CALC(cw[i].x-1,cw[i].y-1));
        }
    }
    return 0;
}

CF 762E

CDQ写法

/*
转化为二维单点更新区间求和
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 2e6 + 5;
const int MXE = 1e7 + 3e6 + 6;
const int INF = 0x3f3f3f3f;

int n, m, N, k, cnt;
LL Ans;
struct lh {
    int x, r, f;
}edge[MXN];
struct lp {
    int flag, x, y, idx, delta;
}cw[MXN], temp[MXN];
int ar[MXN], ans[MXN];
bool cmp(const lh &a, const lh &b) {
    return a.r > b.r;
}
int bit[MXN];
int lowbit(int x){return (x&(-x));}
void ADD(int x,int c,int N){for(; x <= N; x += lowbit(x)) bit[x]+=c;}
int QUERY(int x){if(x<=0)return 0;int ANS = 0;for(; x; x -= lowbit(x)) ANS+=bit[x];return ANS;}

void solve(int l, int r) {
    if(l == r) return ;
    int mid = (l + r) >> 1;
    solve(l, mid); solve(mid + 1, r);
    int j = l;
    for(int i = mid + 1; i <= r; ++i) {
        for(; j <= mid && cw[j].x <= cw[i].x; ++j) {
            if(cw[j].flag == 0) ADD(cw[j].y, 1, N);
        }
        if(cw[i].flag) Ans += QUERY(cw[i].y)*cw[i].delta;
    }
    for(-- j; j >= l; -- j) if(cw[j].flag == 0) ADD(cw[j].y, -1, N);
    int p1 = l, p2 = mid + 1, CNT = l;
    while(p1 <= mid && p2 <= r) {
        if(cw[p1].x <= cw[p2].x) temp[CNT++] = cw[p1], ++p1;
        else temp[CNT++] = cw[p2], ++p2;
    }
    while(p1 <= mid) temp[CNT++] = cw[p1], ++p1;
    while(p2 <= r) temp[CNT++] = cw[p2], ++p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d%d", &edge[i].x, &edge[i].r, &edge[i].f);
        ++ edge[i].f; N = max(N, edge[i].f + m + 1);
    }
    sort(edge + 1, edge + 1 + n, cmp);
    for(int i = 1, a, b, c, d; i <= n; ++i) {
        a = edge[i].x-edge[i].r;b = edge[i].x+edge[i].r;
        c = max(edge[i].f - m, 1); d = edge[i].f + m;//(a, c), (b, d)
        ++cnt; cw[cnt] = {1, b, d, i, 1};
        ++cnt; cw[cnt] = {1, a-1, d, i, -1};
        ++cnt; cw[cnt] = {1, b, c-1, i, -1};
        ++cnt; cw[cnt] = {1, a-1, c-1, i, 1};
        ++cnt; cw[cnt] = {0, edge[i].x, edge[i].f, i, 0};
    }
    solve(1, cnt);
    printf("%lld\n", Ans);
    return 0;
}

树套树写法

/*
由于本题f的变化范围只有10,所以建普通权值线段树,然后暴力查询21次就行。
但是如果f的变化范围很大的话,可能必须得cdq分治或树套树才能写,下面是树套树代码,原理和动态逆序对那题一样。
*/
#include
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 5e5 + 5;
const int MXE = 1e7 + 6;
const int INF = 0x3f3f3f3f;

int n, m, k, N;
LL Ans;
struct lh {
    int x, r, f;
}edg[MXN];
struct lp {
    int l, r, sum;
}cw[MXE];
int Root[MXN], NODE;
int ar[MXN], ans[MXN];
bool cmp(const lh &a, const lh &b) {
    return a.r > b.r;
}
int bit[MXN];
int lowbit(int x){return (x&(-x));}
void ADD(int x,int c,int N){for(; x <= N; x += lowbit(x)) bit[x]+=c;}
int QUERY(int x){if(x<=0)return 0;int ANS = 0;for(; x; x -= lowbit(x)) ANS+=bit[x];return ANS;}

void update(int &p, int x, int l, int r) {
    if(!p) p = ++ NODE;
    ++ cw[p].sum;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(x <= mid) update(cw[p].l, x, l, mid);
    else update(cw[p].r, x, mid+1, r);
}
int query(int rt, int L, int R, int l, int r) {
    if(rt == 0) return 0;
    if(L <= l && r <= R) {
        return cw[rt].sum;
    }
    if(L > r || R < l) return 0;
    int mid = (l + r) >> 1;
    if(L > mid) return query(cw[rt].r, L, R, mid+1, r);
    else if(R <= mid) return query(cw[rt].l, L, R, l, mid);
    else {
        return query(cw[rt].l, L, mid, l, mid) + query(cw[rt].r, mid+1, R, mid + 1, r);
    }
}
int calc(int a, int b, int l, int r) {
    int ans = 0;
    for(; a; a -= lowbit(a)) ans -= query(Root[a], l, r, 1, k);
    for(; b; b -= lowbit(b)) ans += query(Root[b], l, r, 1, k);
    return ans;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d%d", &edg[i].x, &edg[i].r, &edg[i].f);
        ar[++k] = edg[i].x; ar[++k] = edg[i].x-edg[i].r;
        ar[++k] = edg[i].x+edg[i].r; N = max(N, edg[i].f + m);
    }
    sort(edg + 1, edg + 1 + n, cmp);
    sort(ar + 1, ar + 1 + k);
    k = unique(ar + 1, ar + 1 + k) - ar;
    for(int i = 1, l, r; i <= n; ++i) {
        l = lower_bound(ar + 1, ar + k, edg[i].x-edg[i].r) - ar;
        r = lower_bound(ar + 1, ar + k, edg[i].x+edg[i].r) - ar;
        Ans += calc(max(1, edg[i].f-m)-1, edg[i].f + m, l, r);
        l = lower_bound(ar + 1, ar + k, edg[i].x) - ar;
        for(int u = edg[i].f; u <= N; u += lowbit(u)) {
            update(Root[u], l, 1, k);
        }
    }
    printf("%lld\n", Ans);
    return 0;
}

CSUSTOJ 1024:CDQ

#include
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long LL;

const int INF = 0x3f3f3f3f;
const int MXN = 3e6 + 6;

int n, m;
struct lp {
    int ip, x, p, delta, id;
}cw[MXN], temp[MXN];
struct node {
    int opt, x, y, old;
}Fk[MXN];
int ALL;
int ar[MXN], ANS[MXN], QWE[MXN], sum[MXN<<2], br[MXN], is[MXN];
int bit[MXN];
int lowbit(int x){return (x&(-x));}
void bit_add(int x,int c){for(;x <= n+1;x += lowbit(x)) bit[x]^=c;}
int bit_query(int x){int ans = 0;for(;x;x -= lowbit(x))ans^=bit[x];return ans;}
void update(int p,int val,int l,int r,int rt) {
    is[p] += val;
    return;
}
int query(int p,int l,int r,int rt) {
    return is[p];
}
void cdq(int l, int r) {
    if(l == r) return ;
    //printf("[%d, %d]\n", l, r);
    int mid = (l + r) >> 1;
    cdq(l, mid); cdq(mid+1, r);
    int j = l;
    for(int i = mid+1; i <= r; ++i) {
        for(; j <= mid && cw[j].p <= cw[i].p; ++j) {
            if(cw[j].ip == 1) {
                if(cw[j].id != -1) update(cw[j].id, -1, 1, ALL, 1);
                update(cw[j].x, 1, 1, ALL, 1);
            }
        }
        if(cw[i].ip == 2) {
            ANS[cw[i].id] += cw[i].delta*query(cw[i].x, 1, ALL, 1);
            //printf("%d %d %d %d*\n", cw[i].id, cw[i].delta*query(cw[i].x, 1, ALL, 1), cw[i].x, cw[i].delta);
        }
    }
    for(-- j; j >= l; --j) if(cw[j].ip == 1) {
            if(cw[j].id != -1) update(cw[j].id, 1, 1, ALL, 1);
            update(cw[j].x, -1, 1, ALL, 1);
        }
    int p1 = l, p2 = mid+1, cnt = l;
    while(p1 <= mid && p2 <= r) {
        if(p1 <= mid && cw[p1].p <= cw[p2].p) temp[cnt++] = cw[p1], ++ p1;
        else temp[cnt++] = cw[p2], ++ p2;
    }
    while(p1 <= mid) temp[cnt++] = cw[p1], ++ p1;
    while(p2 <= r) temp[cnt++] = cw[p2], ++ p2;
    for(int i = l; i <= r; ++i) cw[i] = temp[i];
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    freopen("E://ADpan//out.out", "w", stdout);
#endif
    //printf("%d\n", (int)(200000*log(1000000)*log(1000000)));
    std::vector vs;
    vs.eb(-1);
    scanf("%d%d", &n, &m);
    assert(n >= 1); assert(n <= 1000000);
    assert(m >= 1); assert(m <= 100000);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &ar[i]), bit_add(i, ar[i]), vs.eb(ar[i]), br[i] = ar[i];
        assert(ar[i] >= 0); assert(ar[i] <= 1000000000);
    }
    for(int i = 1, x, y, opt; i <= m; ++i) {
        scanf("%d%d%d", &opt, &x, &y); Fk[i] = {opt, x, y, 0};
        if(opt == 1) {
            assert(x >= 1); assert(x <= n);
            assert(y >= 0); assert(y <= 1000000000);
            Fk[i].old = ar[x];
            bit_add(x, ar[x]);
            bit_add(x, y);
            ar[x] = y;
            vs.eb(y);
        }else {
            assert(x >= 1); assert(x <= y); assert(y <= n);
            assert(opt == 2);
            Fk[i].old = bit_query(y) ^ bit_query(x-1);
            vs.eb(Fk[i].old);
            //printf("- %d -\n", Fk[i].old);
        }
    }
    sort(all(vs));
    vs.erase(unique(all(vs)), vs.end());
    ALL = vs.size();
    //printf("--%d\n", ALL);
    int cntp = 0, cnta = 0;
    for(int i = 1; i <= n; ++i) {
        cw[++cntp].p = i;
        cw[cntp].ip = 1;
        cw[cntp].x = lower_bound(all(vs), br[i]) - vs.begin() + 1;
        cw[cntp].id = -1;
    }
    for(int i = 1, x, y, opt; i <= m; ++i) {
        opt = Fk[i].opt, x = Fk[i].x, y = Fk[i].y;
        if(opt == 1) {
            cw[++cntp].ip = opt;
            cw[cntp].p = x;
            cw[cntp].id = lower_bound(all(vs), Fk[i].old) - vs.begin() + 1;
            cw[cntp].x = lower_bound(all(vs), y) - vs.begin() + 1;
        }else {
            cw[++cntp].ip = opt;
            cw[cntp].p = x-1;
            cw[cntp].delta = -1;
            cw[cntp].x = lower_bound(all(vs), Fk[i].old) - vs.begin() + 1;
            cw[cntp].id = ++cnta;

            cw[++cntp].ip = opt;
            cw[cntp].p = y;
            cw[cntp].delta = 1;
            cw[cntp].x = cw[cntp-1].x;
            cw[cntp].id = cnta;
            QWE[cnta] = y-x+1;
        }
    }
    cdq(1, cntp);
    for(int i = 1; i <= cnta; ++i) printf("%d\n", QWE[i] - ANS[i]);
    return 0;
}

CSUSTOJ 1026:强制在线树套树

/**
 * Copyright (C), 2019-2019, csust
 * FileName: try
 * Author:   cwolf9
 * Date:     19-4-16 下午6:44
 * Description: ${DESCRIPTION}
 * History:
 *           

整体二分

动态区间第k小

动态区间第k小的n种解法:here
洛谷P2617, ZOJ2112
练习题:洛谷P3332
就很板子的题。
整体二分类似于一些决策单调性的分治,可以解决诸多区间第\(k\)小的问题。
\(solve(l,r,L,R)\)表示当前值域为\([l,r]\),当前操作为\([L,R]\)

我们要对所有操作按照他们对应值域区间进行划分,并递归分治。分治层数只与值域区间相关,我们是带着和这个值域相关的询问向下分治。所以整体二分的复杂度也是很稳定的。

枚举\([L,R]\)

  • 如果当前操作是更新操作:若更新的值在\([l,mid]\)内,则用树状数组在当前更新操作所代表的序列下标位置\(+1\),并将次操作归纳到下一层左区间内;反之归纳到下一层的右区间内。
  • 如果当前操作是查询操作,树状数组询问区间\([cw[i].l,cw[i].r]\)内的值域情况,如果不小于\(cw[i].k\)就归入下一层左区间内;反之减去相应大小并归纳到下一层的右区间内。
  • 终止条件:值域只有一个数,更新相应答案即可。

AC_Code:260ms

const int INF = 0x3f3f3f3f;
const int MXN = 2e5 + 7;
const int MXE = 1e6 + 7;
int n, m;
int bit[MXN];
void bit_add(int x,int c){for(;x <= n+1;x += lowbit(x)) bit[x]+=c;}
int bit_query(int x){int ans = 0;for(;x;x -= lowbit(x))ans+=bit[x];return ans;}
int ar[MXN];
struct lp {
    int l, r, v, id, ip;
}cw[MXN], cw1[MXN], cw2[MXN];
int ans[MXN];
int stk[MXN], top;
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(cw[i].ip == 2) ans[cw[i].id] = l;
        return;
    }
    int mid = (l + r) >> 1, cnt1 = 0, cnt2 = 0;
    top = 0;
    for(int i = L; i <= R; ++i) {
        if(cw[i].ip == 1) {
            if(cw[i].l <= mid) bit_add(cw[i].id, cw[i].v), cw1[++cnt1] = cw[i], stk[++top] = i;
            else cw2[++cnt2] = cw[i];
        }else {
            int k = bit_query(cw[i].r) - bit_query(cw[i].l - 1);
            if(k >= cw[i].v) cw1[++cnt1] = cw[i];
            else cw[i].v -= k, cw2[++cnt2] = cw[i];
        }
    }
    for(int i = 1; i <= top; ++i) bit_add(cw[stk[i]].id, -cw[stk[i]].v);
    for(int i = 1; i <= cnt1; ++i) cw[L + i - 1] = cw1[i];
    for(int i = 1; i <= cnt2; ++i) cw[L + cnt1 + i - 1] = cw2[i];
    solve(l, mid, L, L + cnt1 - 1);
    solve(mid + 1, r, L + cnt1, R);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    int tim = read();
    while(tim --) {
        n = read(), m = read();
        int tot = 0, p = 0;
        for(int i = 1; i <= n; ++i) ar[i] = read(), cw[++ tot] = {ar[i], 0, 1, i, 1};
        char s[2];
        int l, r, k;
        for(int i = 1; i <= m; ++i) {
            scanf("%s", s);
            if (s[0] == 'Q') {
                l = read(), r = read(), k = read();
                cw[++tot] = {l, r, k, ++ p, 2};
            }else {
                l = read(), r = read();
                cw[++tot] = {ar[l], 0, -1, l, 1};
                cw[++tot] = {ar[l] = r, 0, 1, l, 1};
            }
        }
        solve(0, INF, 1, tot);
        for(int i = 1; i <= p; ++i) printf("%d\n", ans[i]);
    }
    return 0;
}

P3332 [ZJOI2013]K大数查询

坑点:会爆栈导致\(mle\)\(mle\)是因为负数二分递归原因
mle的原因是负数分治递归下去的时候死循环了,就是(l,r)没变过

  • solution1:如果现在操作里没有询问操作就break
  • solution2:如果递归层数大于20层就break,因为死循环只出现在负数,只有插入会出现负数,可以肯定死循环的操作里没有循环操作
  • solution3:既然负数会出问题,就把负数变成整数呗

这题和上面那题唯一的区别就是单点更新变成了区间更新,用一个可以区间加区间赋零的数据结构就行了。
可以树状数组也可以线段树(线段树就用两个lazy标记,一个区间加,一个区间赋值,注意区间赋值的lazy标记优先级比较高)
代码:1, 2
AC_Code

const int MXN = 1e5 + 7;
const int MXE = 1e6 + 7;
int n, m;
//sum[i] = sigma(ar[x])+(i+1)*sigma(delta[x])-sigma(x*delta[x])
//delta[]是差分数组
struct FenwickTree {
    static const int MAXN = 1e5 + 6;
    LL delta[MAXN], deltai[MAXN];
    void add1(int x, int v) {
        while (x <= n + 10) {
            delta[x] += v;
            x += lowbit(x);
        }
    }
    void add2(int x, int v) {
        while (x <= n + 10) {
            deltai[x] += v;
            x += lowbit(x);
        }
    }
    LL query1(int x) {
        LL sum = 0;
        while (x > 0) {
            sum += delta[x];
            x -= lowbit(x);
        }
        return sum;
    }
    LL query2(int x) {
        LL sum = 0;
        while (x > 0) {
            sum += deltai[x];
            x -= lowbit(x);
        }
        return sum;
    }
    void update(int l, int r, int x) {
        add1(l, x);
        add1(r + 1, -x);
        add2(l, l * x);
        add2(r + 1, -x * (r + 1));
    }
    LL range(int l, int r) {
        LL sum1 = l * query1(l - 1) - query2(l - 1);
        LL sum2 = (r + 1) * query1(r) - query2(r);
        return sum2 - sum1;
    }
}bit;
struct lp {
    int l, r;
    LL v;
    int id, ip;
    lp(){}
    lp(int _l, int _r, LL _v, int _id, int _ip) {
        l = _l, r = _r, v = _v, id = _id, ip = _ip;
    }
}cw[MXN], cw1[MXN], cw2[MXN];
int ans[MXN];
int stk[MXN], top;
void solve(int l, int r, int L, int R, int d) {
    if(d > 18) return;
    if(l > r || L > R) return;
    if(l == r) {
        for(int i = L; i <= R; ++i) if(cw[i].ip == 2) ans[cw[i].id] = l;
        return;
    }
    int mid = (l + r) / 2, cnt1 = 0, cnt2 = 0;
    top = 0;
    bool fl = false, fr = false;
    for(int i = L; i <= R; ++i) {
        if(cw[i].ip == 1) {
            if(cw[i].v > mid) bit.update(cw[i].l, cw[i].r, 1), cw1[++cnt1] = cw[i], stk[++top] = i;
            else cw2[++cnt2] = cw[i];
        }else {
            LL k = bit.range(cw[i].l, cw[i].r);
            if(k >= cw[i].v) cw1[++cnt1] = cw[i], fr = true;
            else cw[i].v -= k, cw2[++cnt2] = cw[i], fl = true;
        }
    }
    for(int i = 1; i <= top; ++i) bit.update(cw[stk[i]].l, cw[stk[i]].r, -1);
    for(int i = 1; i <= cnt2; ++i) cw[L + i - 1] = cw2[i];
    for(int i = 1; i <= cnt1; ++i) cw[L + cnt2 + i - 1] = cw1[i];
    if(fl) solve(l, mid, L, L + cnt2 - 1, d + 1);
    if(fr) solve(mid + 1, r, L + cnt2, R, d + 1);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
//    freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
//    int tim = 1;
    n = read(), m = read();
    int p = 0;
    int l, r, opt;
    LL k;
    for(int i = 1; i <= m; ++i) {
        opt = read();
        if (opt == 1) {
            l = read(), r = read(), k = read();
            cw[i] = lp(l, r, k, l, 1);
        }else {
            l = read(), r = read(), k = read();
            cw[i] = lp(l, r, k, ++ p, 2);
        }
    }
    solve(-n, n, 1, m, 1);
    for(int i = 1; i <= p; ++i) printf("%d\n", ans[i]);
    return 0;
}

你可能感兴趣的:(CDQ分治&整体二分学习个人小结)