[P3157] [CQOI2011]动态逆序对

洛谷题目链接:[CQOI2011]动态逆序对

题目描述

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

输入输出格式

输入格式:

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

输出格式:

输出包含m行,依次为删除每个元素之前,逆序对的个数。

输入输出样例

输入样例#1:

5 4
1
5
3
4
2
5
1
4
2

输出样例#1:

5
2
2
1

样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

说明

N<=100000 M<=50000

一句话题意: 给出一个\(1\)~\(n\)的排列,每次问每次删除一个数前逆序对个数.

题解: 最近刚学的树套树,于是找了道题想练习一下 (然后就被这常数给卡到心态炸裂,树套树害人,不要太信它了!!!).

还是来讲一下做法吧.如果直接求逆序对相信大家都会写,可以直接通过归并排序或是树状数组统计每个数前面比它大的,或是统计后面比它小的.

那么如果带删除要怎么搞呢?对于树套树来说,可以直接在这个区间删除这个数字,然后每次减去这个数字与别的数字作出的贡献,就可以得到这一次的值.

如果写树套树真的挺模板的.但是会被卡常.这里我采用了直接插入\(O(n)\)一颗平衡树的方法来减小常数,然后第一遍逆序对直接用归并排序求出.之后每次删除就在每个区间内找到这个节点删除,并减去这个点之前比它大的和之后比它小的个数就得到了下一次答案.

这题一点都不推荐用树套树写,早日去学整体二分/带修改主席树吧.

#include<bits/stdc++.h>
#define ll(x) (x<<1)
#define rr(x) (x<<1|1)
using namespace std;
const int N=100000+5;

int n, m, a[N], b[N], c[N], q[N], root[N*4], stk[N], top = 0, r1, r2, r3, vis[N];
long long ans = 0;

namespace treap{
    int cnt = 0;
    struct treap_tree{
		int ch[2], size, val, rd;
    }t[N*20];
    
    inline void up(int x){ t[x].size = t[t[x].ch[0]].size+t[t[x].ch[1]].size+1; }
    
    inline int newnode(int val){
		t[++cnt].val = val; t[cnt].rd = rand(), t[cnt].size = 1;
		return cnt;
    }
    
    inline void split(int x, int val, int &a, int &b){
		if(x == 0){ a = b = 0; return; }
		if(val < t[x].val) b = x, split(t[x].ch[0], val, a, t[x].ch[0]);
		else a = x, split(t[x].ch[1], val, t[x].ch[1], b); up(x);
    }

    inline int merge(int x, int y){
		if(x == 0 || y == 0) return x+y;
		if(t[x].rd < t[y].rd){
		    t[x].ch[1] = merge(t[x].ch[1], y);
		    up(x); return x;
		} else {
		    t[y].ch[0] = merge(x, t[y].ch[0]);
		    up(y); return y;
		}
    }

    inline int build(int l, int r){
		top = 0;
		for(int i=l;i<=r;i++) c[i] = a[i];
		sort(c+l, c+r+1);
		for(int i=l;i<=r;i++){
		    register int temp = newnode(c[i]), last = 0;
		    while(top && t[stk[top]].rd > t[temp].rd)
			up(stk[top]), last = stk[top], stk[top--] = 0;
		    if(top) t[stk[top]].ch[1] = temp;
		    t[temp].ch[0] = last; stk[++top] = temp;
		}
		while(top) up(stk[top--]); return stk[1];
    }
    
    inline void insert(int x, int val){
		split(root[x], val, r1, r2);
		root[x] = merge(r1, merge(newnode(val), r2));
    }
    
    inline int get_less(int x, int val){
		split(root[x], val-1, r1, r2);
		register int res = t[r1].size;
		root[x] = merge(r1, r2);
		return res;
    }

    inline int get_more(int x, int val){
		split(root[x], val, r1, r2);
		register int res = t[r2].size;
		root[x] = merge(r1, r2);
		return res;
    }
    
    inline void delet(int x, int val){
		split(root[x], val, r1, r3);
		split(r1, val-1, r1, r2);
		r2 = merge(t[r2].ch[0], t[r2].ch[1]);
		root[x] = merge(r1, merge(r2, r3));
    }
}

namespace seg{
    struct segment_tree{
		int l, r;
    }t[N*4];
    
    inline void build(int x, int l, int r){
		t[x].l = l, t[x].r = r; root[x] = treap::build(l, r);
		if(l == r) return; register int mid = (l+r>>1);
		build(ll(x), l, mid); build(rr(x), mid+1, r);
    }
    
    inline int update(int x, int pos){
		if(t[x].l == pos && pos == t[x].r){
		    register int res = treap::t[root[x]].val;
		    treap::delet(x, res); return res;
		}
		register int mid = (t[x].l+t[x].r>>1), res;
		if(pos <= mid) res = update(ll(x), pos);
		else res = update(rr(x), pos);
		treap::delet(x, res); return res;
    }

    inline int query_less(int x, int l, int r, int val){
		if(l <= t[x].l && t[x].r <= r) return treap::get_less(x, val);
		if(r < t[x].l || t[x].r < l) return 0;
		return query_less(ll(x), l, r, val)+query_less(rr(x), l, r, val);
    }
    
    inline int query_more(int x, int l, int r, int val){
		if(l <= t[x].l && t[x].r <= r) return treap::get_more(x, val);
		if(r < t[x].l || t[x].r < l) return 0;
		return query_more(ll(x), l, r, val)+query_more(rr(x), l, r, val);
    }
}

inline int gi(){
    int ans = 0, f = 1; char i = getchar();
    while(i<'0' || i>'9'){ if(i == '-') f = -1; i = getchar(); }
    while(i>='0' && i<='9') ans = ans*10+i-'0', i = getchar();
    return ans * f;
}

inline void merge_sort(int l, int r){
    if(l == r) return;
    register int mid = (l+r>>1), i = l, j = mid+1, cnt = 0;
    merge_sort(l, mid); merge_sort(mid+1, r);
    while(i <= mid && j <= r){
		if(b[i] < b[j]) q[++cnt] = b[i++];
		else q[++cnt] = b[j++], ans += mid+1-i;
    }
    while(i <= mid) q[++cnt] = b[i++];
    while(j <= r) q[++cnt] = b[j++];
    for(int i=1;i<=cnt;i++) b[l+i-1] = q[i];
}

int main(){
    freopen("data.in", "r", stdin);
    int x; n = gi(), m = gi(); srand(19260817);
    for(int i=1;i<=n;i++) a[i] = gi(), vis[a[i]] = i;
    memcpy(b, a, sizeof(b));
    seg::build(1, 1, n);
    merge_sort(1, n);
    for(int i=1;i<=m;i++){
		printf("%lld\n", ans);
		x = gi();
		if(vis[x] > 1) ans -= seg::query_more(1, 1, vis[x]-1, x);
		if(vis[x] < n) ans -= seg::query_less(1, vis[x]+1, n, x);
		seg::update(1, vis[x]);
    }
    return 0;
}
posted @ 2018-07-24 20:42  Brave_Cattle  阅读(275)  评论(0编辑  收藏  举报