码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 4053 Couleur

时间:2018-09-18 00:15:32      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:oid   head   find   build   printf   const   print   efi   signed   

4053

思路:

主席树

先分别求前缀和后缀的逆序数

然后要求某一段的逆序数,就可以根据前缀或着后缀根据容斥求出答案,

这样需要枚举这一段中的数,求之前或者之后有多少个比他大或比他小的数,

这个可以通过用主席数维护权值线段树来做

然后每次枚举断开后小的那段区间,这样最多需要枚举n*log(n)次

复杂度:n*log(n)*log(n)

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pii pair<int, int>
#define piii pair<pii, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
//head

const int N = 1e5 + 10, M = 2e6 + 10;
int a[N], p[N], root[N], bit[N], lson[M], rson[M], value[M], tot = 0, n;
LL tmp[N], ans[N], pre[N], suf[N];
multiset<LL> s;
void build(int &x, int l, int r) {
    x = ++tot;
    if(l == r) {
        value[x] = 0;
        return ;
    }
    int m = l+r >> 1;
    build(lson[x], l, m);
    build(rson[x], m+1, r);
    value[x] = value[lson[x]] + value[rson[x]];
}
void update(int old, int &x, int p, int v, int l, int r) {
    x = ++tot;
    lson[x] = lson[old], rson[x] = rson[old], value[x] = value[old] + v;
    if(l == r) return ;
    int m = l+r >> 1;
    if(p <= m) update(lson[x], lson[x], p, v, l, m);
    else update(rson[x], rson[x], p, v, m+1, r);
}
int query(int L, int R, int x, int l, int r) {
    if(L > R) return 0;
    if(L <= l && r <= R) return value[x];
    int m = l+r >> 1, ans = 0;
    if(L <= m) ans += query(L, R, lson[x], l, m);
    if(R > m) ans += query(L, R, rson[x], m+1, r);
    return ans;
}
void add(int x, int v) {
    while(x <= n+1) bit[x] += v, x += x&-x;
}
int sum(int x) {
    int ans = 0;
    while(x) ans += bit[x], x -= x&-x;
    return ans;
}
int Find_pre(int pos) {
    int l = 1, r = pos, m = l+r >> 1;
    while(l < r) {
        if(sum(pos) - sum(m-1) > 0) l = m + 1;
        else r = m;
        m = l+r >> 1;
    }
    return m;
}
int Find_nxt(int pos) {
    int l = pos, r = n, m = l+r+1 >> 1;
    while(l < r) {
        if(sum(m) - sum(pos-1) > 0) r = m - 1;
        else l = m;
        m = l+r+1 >> 1;
    }
    return m;
}
void solve(int l, int m, int r) {
    if(l == r) return ;
    else if(l + 1 == r) {
        if(l == m) tmp[l] = 0, s.insert(0);
        else tmp[l-1] = 0, s.insert(0);
    }
    else {
        if(l == m) {
            LL t = tmp[l-1];
            t -= (query(1, a[m]-1, root[r], 1, n) - query(1, a[m]-1, root[l], 1, n));
            tmp[l] = t;
            s.insert(t);
        }
        else if(r == m) {
            LL t = tmp[l-1] - (query(a[m]+1, n, root[r-1], 1, n) - query(a[m]+1, n, root[l-1], 1, n));
            tmp[l-1] = t;
            s.insert(t);
        }
        else {
            LL t = tmp[l-1], t1, t2;
            if(m-l+1 < r-m) {
                t1 = pre[m-1] - pre[l-1];
                for (int i = l; i < m; i++) {
                    t1 -= query(a[i]+1, n, root[l-1], 1, n);
                }

                t2 = t - t1;
                for (int i = l; i < m; i++) {
                    t2 -= query(1, a[i]-1, root[r], 1, n) - query(1, a[i]-1, root[m-1], 1, n);
                }
                t2 -= query(1, a[m]-1, root[r], 1, n) - query(1, a[m]-1, root[m], 1, n);
             }
            else {
                t2 = suf[m+1] - suf[r+1];
                for (int i = m+1; i <= r; i++) {
                    if(r+1 <= n) t2 -= query(1, a[i]-1, root[n], 1, n) - query(1, a[i]-1, root[r], 1, n);
                }

                t1 = t - t2;
                for (int i = m+1; i <= r; i++) {
                    t1 -= query(a[i]+1, n, root[m], 1, n) - query(a[i]+1, n, root[l-1], 1, n);
                }
                t1 -= query(a[m]+1, n, root[m-1], 1, n) - query(a[m]+1, n, root[l-1], 1, n);
            }
            tmp[l-1] = t1;
            tmp[m] = t2;
            s.insert(t1);
            s.insert(t2);
        }
    }

}
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
        pre[0] = suf[n+1] = 0; 
        s.clear();
        tot = 0;
        build(root[0], 1, n);
        for (int i = 1; i <= n; i++) update(root[i-1], root[i], a[i], 1, 1, n);
        for (int i = n; i >= 1; i--) {
            suf[i] = suf[i+1] + query(1, a[i]-1, root[n], 1, n) - query(1, a[i]-1, root[i], 1, n);
        }
        for (int i = 1; i <= n; i++) {
            pre[i] = pre[i-1] + query(a[i]+1, n, root[i-1], 1, n);
        }
        for (int i = 0; i <= n+1; i++) bit[i] = 0;
        tmp[0] = suf[1];
        s.insert(tmp[0]);
        for (int i = 1; i <= n; i++) {
            ans[i] = *s.rbegin();
            int t = ans[i]^p[i];
            int l = Find_pre(t), r = Find_nxt(t);
            s.erase(s.find(tmp[l-1]));
            solve(l, t, r);
            add(t, 1);
        }
        for (int i = 1; i <= n; i++) printf("%lld%c", ans[i], " \n"[i==n]);
    }
    return 0;
}

 

ZOJ 4053 Couleur

标签:oid   head   find   build   printf   const   print   efi   signed   

原文地址:https://www.cnblogs.com/widsom/p/9665429.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!