思路:
主席树
先分别求前缀和后缀的逆序数
然后要求某一段的逆序数,就可以根据前缀或着后缀根据容斥求出答案,
这样需要枚举这一段中的数,求之前或者之后有多少个比他大或比他小的数,
这个可以通过用主席数维护权值线段树来做
然后每次枚举断开后小的那段区间,这样最多需要枚举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], " "[i==n]); } return 0; }