「CQOI2011」动态逆序对

「CQOI2011」动态逆序对

传送门
树套树。
删除一个位置的元素带来的减损数等于他前面大于它的和后面小于它的,然后这个直接树状数组套主席树维护一下就好了。
参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

typedef long long LL;
const int _ = 1e5 + 5, __ = 1e7 + 5;

int n, q, a[_], pos[_];
int tot, rt[_], lc[__], rc[__], t1[_], t2[_]; LL cnt[__];

inline void update(int& p, int x, int v, int l = 1, int r = n) {
    if (!p) p = ++tot; cnt[p] += v;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (x <= mid) update(lc[p], x, v, l, mid);
    else update(rc[p], x, v, mid + 1, r);
}

inline LL Query(int l, int r, int x, int opt) {
    int c1 = 0, c2 = 0; --l;
    for (rg int i = l; i >= 1; i -= i & -i) t1[++c1] = rt[i];
    for (rg int i = r; i >= 1; i -= i & -i) t2[++c2] = rt[i];
    l = 1, r = n;
    LL res = 0;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (x <= mid) {
            if (opt == 0) {
                for (rg int i = 1; i <= c1; ++i) res -= cnt[rc[t1[i]]];
                for (rg int i = 1; i <= c2; ++i) res += cnt[rc[t2[i]]];
            }
            for (rg int i = 1; i <= c1; ++i) t1[i] = lc[t1[i]];
            for (rg int i = 1; i <= c2; ++i) t2[i] = lc[t2[i]];
            r = mid;
        } else {
            if (opt == 1) {
                for (rg int i = 1; i <= c1; ++i) res -= cnt[lc[t1[i]]];
                for (rg int i = 1; i <= c2; ++i) res += cnt[lc[t2[i]]];
            }
            for (rg int i = 1; i <= c1; ++i) t1[i] = rc[t1[i]];
            for (rg int i = 1; i <= c2; ++i) t2[i] = rc[t2[i]];
            l = mid + 1;
        }
    }
    return res;
}

int main() {
    read(n), read(q);
    LL ans = 0;
    for (rg int i = 1; i <= n; ++i) {
        read(a[i]), pos[a[i]] = i;
        ans += Query(1, i - 1, a[i], 0);
        for (rg int j = i; j <= n; j += j & -j) update(rt[j], a[i], 1);
    }
    for (rg int x; q--; ) {
        printf("%lld\n", ans);
        read(x);
        ans -= Query(1, pos[x] - 1, x, 0);
        ans -= Query(pos[x] + 1, n, x, 1);
        for (rg int j = pos[x]; j <= n; j += j & -j) update(rt[j], x, -1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zsbzsb/p/12231671.html

时间: 2024-08-30 10:06:23

「CQOI2011」动态逆序对的相关文章

bzoj3295【CQOI2011】动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3122  Solved: 986 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数

【CQOI2011】动态逆序对 BZOJ3295

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ 3295 【Cqoi2011】 动态逆序对

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. HINT N<=100000 M<

【BZOJ3295】【CQOI2011】动态逆序对

cdq分治经典例题,然而智商掉线傻逼错误坑了两天 原题: 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. N<=100000 M<=50000 此题修改和询问绑定完全离线,可以直接倒序变成插入,然后就是三维数星星辣(? ?????)? x为下标,y为值,z为时间轴,x排序,z_cdq分治,y树状数组 不用搞两次cdq分治,每次按x递增查找比y大的

【BZOJ】【3295】【CQOI2011】动态逆序对

树套树 Orz zyf神犇 时光倒流……逆序处理,将删点改为加点,动态维护序列. 由于是动态,要加点,所以用树状数组:同时又需要求序列中求比当前元素大/小的元素个数,所以要用平衡树. 所以方法就是在树状数组的每个节点上维护一棵这个节点表示的区间的平衡树. 为什么这样做是对的呢?因为求<k的元素个数这类操作满足区间加法,所以可以把多棵平衡树上的结果(一棵平衡树表示一个区间)加起来,就是整个区间的结果. (我一开始想成带修改的区间第K大那种做法了……就是树状数组套权值线段树……sigh) WA:an

[CQOI2011]动态逆序对

P1347 - [CQOI2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数. 以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个

主席树初探 &amp; bzoj 3295: [Cqoi2011] 动态逆序对 题解

[原题] 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 778  Solved: 263 [Submit][Status] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元

【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

[BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的

【BZOJ 3295】 [Cqoi2011]动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1373  Solved: 465 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数