• Luogu 3759 [TJOI2017]不勤劳的图书管理员


    再也不作死写FhqTreap作内层树了,卡的不如暴力呜呜呜…… 

    题意翻译:给一个序列,每个下标包含两个属性$a$和$v$,求第一个属性与下标形成的所有逆序对的第二个属性和,给出$m$个交换两个下标的操作,每次操作之后查询。

    考虑一下交换之后会发生什么:

    假设这次要交换$x$和$y$,使$x leq y$。

    发现交换之后$x, y$和$x$的左边的数和$y$右边的数构成的逆序对产生的贡献不变,发生变化的是中间的数。

    那么问题就简单了,只要先消去中间的数和$x, y$的贡献,具体来说就是$[x + 1, y - 1]$这个区间中$a_{i}$比$a_{x}$小的$b_{i}$和,以及$a_{i}$比$a_{y}$大的$b_{i}$和。

    发现$(x, y)$可能也会构成一个逆序对,拎出来判一下可以保证这一对只被计算一次。

    然后算一下交换之后产生的贡献,方法类似。

    树套树维护即可。

    时间复杂度$O(nlog^{2}n)$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 5e4 + 5;
    const int M = 2e7 + 5;
    const ll P = 1e9 + 7;
    
    int n, m, a[N];
    ll v[N], ans = 0LL;
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    template <typename T>
    inline void swap(T &x, T &y) {
        T t = x; x = y; y = t;
    }
    
    namespace BinaryIndexTree {
        int cnt[N]; ll s[N];
        
        #define lowbit(x) (x & (-x))
        
        inline void modifyS(int p, ll val) {
            for(; p <= n; p += lowbit(p)) s[p] = (s[p] + val) % P;
        }
        
        inline void modifyC(int p) {
            for(; p <= n; p += lowbit(p)) cnt[p]++;
        }
        
        inline ll getSum(int p) {
            ll res = 0;
            for(; p > 0; p -= lowbit(p)) res = (res + s[p]) % P;
            return res;
        }
        
        inline int getCnt(int p) {
            int res = 0;
            for(; p > 0; p -= lowbit(p)) res += cnt[p];
            return res;
        }
        
        #undef lowbit
        
    } using namespace BinaryIndexTree;
    
    namespace Tree {
        int nodeCnt, root[N * 30];
        struct Node {
            int lc, rc, siz;
            ll sum;
        } s[M];
        
        #define mid ((l + r) >> 1)
        
        inline void up(int p) {
            if(!p) return;
            s[p].siz = s[s[p].lc].siz + s[s[p].rc].siz;
            s[p].sum = (s[s[p].lc].sum + s[s[p].rc].sum) % P;
        }
        
        void modify(int &p, int l, int r, int x, ll selV) {
            if(!p) p = ++nodeCnt;
            if(l == r) {
                s[p].siz = (selV != -1);
                s[p].sum = (selV == -1 ? 0 : selV % P);
                return;
            }
            
            if(x <= mid) modify(s[p].lc, l, mid, x, selV);
            else modify(s[p].rc, mid + 1, r, x, selV);
            up(p);
        }
        
        ll query(int p, int l, int r, int x, int y, ll selV) {
            if(!p) return 0LL;
            if(x <= l && y >= r) return (selV * s[p].siz % P + s[p].sum) % P;
            
            ll res = 0LL;
            if(x <= mid) res = (res + query(s[p].lc, l, mid, x, y, selV)) % P;
            if(y > mid) res = (res + query(s[p].rc, mid + 1, r, x, y, selV)) % P;
            return res;
        }
        
        #define lowbit(p) (p & (-p))
        
        inline void change(int p, int val, ll selV) {
            for(; p <= n; p += lowbit(p))
                modify(root[p], 1, n, val, selV);
        }
        
        inline void clear(int p, int val) {
            for(; p <= n; p += lowbit(p))
                modify(root[p], 1, n, val, -1);
        }
        
        inline ll ask(int p, int v, ll selV, int type) {
            ll res = 0LL;
            for(; p > 0; p -= lowbit(p)) {
                if(type) res = (res + query(root[p], 1, n, v + 1, n, selV)) % P;
                else res = (res + query(root[p], 1, n, 1, v - 1, selV)) % P;
            }
            return res;
        }
        
        inline ll qSum(int l, int r, int v, ll selV, int type) {
            return (ask(r, v, selV, type) - ask(l - 1, v, selV, type) + P) % P;
        }
        
    } using namespace Tree;
    
    int main() {
        read(n), read(m);
        nodeCnt = 0;
        for(int i = 1; i <= n; i++) {
            read(a[i]), read(v[i]);
            ans = (ans + (getSum(n) - getSum(a[i]) + P) % P + P + v[i] * (getCnt(n) - getCnt(a[i])) % P + P) % P;
            modifyS(a[i], v[i]), modifyC(a[i]);
            change(i, a[i], v[i]);
        }
        
        for(int x, y; m--; ) {
            read(x), read(y);
            if(x == y) {
                printf("%lld
    ", ans);
                continue;
            }
            if(x > y) swap(x, y);
            
            ll res = 0LL;
            if(x + 1 <= y - 1) {
                res = (res + qSum(x + 1, y - 1, a[y], v[y], 1)) % P;
                res = (res + qSum(x + 1, y - 1, a[x], v[x], 0)) % P;
            }
            if(a[y] < a[x]) res = ((res + v[x]) % P + v[y]) % P;
            
            ans = (ans - res + P) % P;
            
            res = 0LL;
            if(x + 1 <= y - 1) {
                res = (res + qSum(x + 1, y - 1, a[y], v[y], 0)) % P;
                res = (res + qSum(x + 1, y - 1, a[x], v[x], 1)) % P;
            }
            
            if(a[y] > a[x]) res = ((res + v[x]) % P + v[y]) % P;
            ans = (ans + res) % P;
            
            printf("%lld
    ", ans);
            
            clear(x, a[x]), clear(y, a[y]);
            change(x, a[y], v[y]), change(y, a[x], v[x]);
            swap(a[x], a[y]), swap(v[x], v[y]);
        }
        
        return 0;
    }
    树状数组套线段树(100 pts)
    // luogu-judger-enable-o2
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    typedef long long ll;
    
    const int N = 5e4 + 5;
    const int M = 2e7 + 5;
    const ll P = 1e9 + 7;
    
    int n, m, a[N];
    ll v[N], ans = 0;
    
    namespace FhqTreap {
        int root[M], nodeCnt, ch[M][2], pri[M], siz[M];
        ll key[M], sum[M], sel[M];
        
        #define lc ch[p][0]
        #define rc ch[p][1]
        
        inline void up(int p) {
            if(p) {
                siz[p] = siz[lc] + siz[rc] + 1;
                sum[p] = (sum[lc] % P + sum[rc] % P + sel[p] % P) % P;
            }
        }
        
        inline int newnode(ll val, ll selV) {
            ++nodeCnt;
            key[nodeCnt] = val, sum[nodeCnt] = sel[nodeCnt] = selV;
            pri[nodeCnt] = rand(), siz[nodeCnt] = 1;
            return nodeCnt;
        }
        
        void split(int p, ll val, int &x, int &y) {
            if(!p) x = y = 0;
            else {
                if(val >= key[p])
                    x = p, split(rc, val, rc, y);
                else 
                    y = p, split(lc, val, x, lc);
                up(p);
            }
        }
        
        int merge(int x, int y) {
            if(!x || !y) return x + y;
            else {
                if(pri[x] < pri[y]) {
                    ch[x][1] = merge(ch[x][1], y);
                    up(x);
                    return x;
                } else {
                    ch[y][0] = merge(x, ch[y][0]);
                    up(y);
                    return y;
                }    
            }    
        }
        
        inline void insert(int rt, ll val, ll selV) {
            if(!root[rt]) {
                root[rt] = newnode(val, selV);
                return;
            }
            int x, y;
            split(root[rt], val, x, y);
            root[rt] = merge(x, merge(newnode(val, selV), y));
        }
        
        inline void remove(int rt, ll val) {
            int x, y, z;
            split(root[rt], val, x, y);
            split(x, val - 1, x, z);
            z = merge(ch[z][0], ch[z][1]);
            root[rt] = merge(merge(x, z), y);
        }
        
        inline ll ask(int rt, ll val, ll selV, int type) {
            int x, y; ll res;
            if(type) {
                split(root[rt], val, x, y);
                res = (selV * siz[x] % P + sum[x]) % P; 
            } else {
                split(root[rt], val, x, y);
                res = (selV * siz[y] % P + sum[y]) % P;
            }
            root[rt] = merge(x, y);
            return res % P;
        }
        
        void Pi(int p, int *arr) {
            if(lc) Pi(lc, arr);
            printf("%d ", arr[p]);
            if(rc) Pi(rc, arr);
        }
        
        #undef lc
        #undef rc
    };
    
    namespace SegT {
        using namespace FhqTreap;
        
        #define lc p << 1
        #define rc p << 1 | 1
        #define mid ((l + r) >> 1)
        
        void ins(int p, int l, int r, int x, ll val, ll selV) {
            insert(p, val, selV);
            if(l == r) return;
            if(x <= mid) ins(lc, l, mid, x, val, selV);
            else ins(rc, mid + 1, r, x, val, selV);
        }
        
        void del(int p, int l, int r, int x, ll val) {
            remove(p, val);
            if(l == r) return;
            if(x <= mid) del(lc, l, mid, x, val);
            else del(rc, mid + 1, r, x, val);
        }
        
        ll query(int p, int l, int r, int x, int y, ll val, ll selV, int type) {
            if(x <= l && y >= r) return ask(p, val, selV, type) % P;
            
            ll res = 0;
            if(x <= mid) res = (res + query(lc, l, mid, x, y, val, selV, type)) % P;
            if(y > mid) res = (res + query(rc, mid + 1, r, x, y, val, selV, type)) % P;
            return res;
        }
        
        void print(int p, int l, int r, int *arr) {
            Pi(root[p], arr), printf("
    ");
            if(l == r) return;
            print(lc, l, mid, arr), print(rc, mid + 1, r, arr);
        }
        
    } using namespace SegT;
    
    template <typename T>
    inline void swap(T &x, T &y) {
        T t = x;
        x = y;
        y = t;
    }
    
    namespace IOstream{
        const int L = 1 << 15;
        
        char buffer[L], *S, *T;
        
        inline char Getchar() {
            if(S == T) {
                T = (S = buffer) + fread(buffer, 1, L, stdin);
                if(S == T) return EOF;
            }
            return *S++;
        }
        
        template <class T> 
        inline void read(T &X) {
            char ch; T op = 1;
            for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar())
                if(ch == '-') op = -1;
            for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) 
                X = (X << 1) + (X << 3) + ch - '0'; 
            X *= op;
        }
        
        template <typename T>
        inline void write(T x)
        {
            T sta[15]; int len = 0;
            if(x < 0) putchar('-'), x = -x;
            if(x == 0) {
                putchar('0');
                return;
            }
            for(; x > 0; sta[++len] = x % 10, x /= 10);
            for(int i = len; i >= 1; i--) putchar(sta[i] + '0');
        }
        
    } using namespace IOstream;
    
    namespace BinaryIndexTree {
        int cnt[N]; ll s[N];
        
        #define lowbit(x) (x & (-x))
        
        inline void modifyS(int p, ll val) {
            for(; p <= n; p += lowbit(p)) s[p] = (s[p] + val) % P;
        }
        
        inline void modifyC(int p) {
            for(; p <= n; p += lowbit(p)) cnt[p]++;
        }
        
        inline ll getSum(int p) {
            ll res = 0;
            for(; p > 0; p -= lowbit(p)) res = (res + s[p]) % P;
            return res;
        }
        
        inline int getCnt(int p) {
            int res = 0;
            for(; p > 0; p -= lowbit(p)) res += cnt[p];
            return res;
        }
        
    } using namespace BinaryIndexTree;
    
    int main() {
    //    freopen("1.in", "r", stdin);
    //    freopen("mine.out", "w", stdout);
        
    //    srand(19260817);
        
        read(n), read(m);
        nodeCnt = 0;
        for(int i = 1; i <= n; i++) {
            read(a[i]), read(v[i]);
            ans = (ans + (getSum(n) - getSum(a[i]) + P) % P + P + v[i] * (getCnt(n) - getCnt(a[i])) % P + P) % P;
            modifyS(a[i], v[i]), modifyC(a[i]);
            ins(1, 1, n, i, a[i], v[i]);
        }
        
    //    printf("%d
    ", ans);
        
        for(int x, y; m--; ) {
            read(x), read(y);
            if(x == y) {
                printf("%lld
    ", ans);
                continue;
            }
            if(x > y) swap(x, y);
            
            ll res = 0;
            if(x + 1 <= y - 1) {
                res = (res + query(1, 1, n, x + 1, y - 1, a[y], v[y], 0)) % P;
                res = (res + query(1, 1, n, x + 1, y - 1, a[x], v[x], 1)) % P; 
            }
            if(a[y] < a[x]) res = (res % P + v[x] % P + v[y] % P) % P;
            ans = (ans - res + P) % P;
            
            res = 0;
            if(x + 1 <= y - 1) {
                res = (res + query(1, 1, n, x + 1, y - 1, a[y], v[y], 1)) % P;
                res = (res + query(1, 1, n, x + 1, y - 1, a[x], v[x], 0)) % P; 
            }
            if(a[y] > a[x]) res = (v[y] % P + v[x] % P + res % P) % P;
            ans = (ans + res) % P;
            
            write(ans), puts("");
            
            del(1, 1, n, x, a[x]), del(1, 1, n, y, a[y]);
            ins(1, 1, n, y, a[x], v[x]), ins(1, 1, n, x, a[y], v[y]);
            swap(a[x], a[y]), swap(v[x], v[y]);
            
    /*        print(1, 1, n, key), printf("
    ");
            print(1, 1, n, sel), printf("
    ");   */
        }
        
        return 0;
    }
    线段树套fhqTreap (20 pts)
  • 相关阅读:
    LeetCode 12. 整数转罗马数字
    [Python] for in range()使用以及列表字符串反转方法
    组合数问题
    「BJOI2020」封印
    数据结构优化建图
    小Q与找茬
    无旋Treap学习
    jzoj5679
    数星星
    凸性
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9577938.html
Copyright © 2020-2023  润新知