【bzoj3295】[Cqoi2011]动态逆序对 树状数组套主席树

Description

对于序列A,它的逆序对数定义为满足i

Input

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

Output

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

Sample Input

5 4

1

5

3

4

2

5

1

4

2

Sample Output

5

2

2

1

样例解释

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

HINT

N<=100000 M<=50000

Source

经典题…

每删一个数就把它前面比他大的 后面比他小的的贡献减去

而这些很好实现…主席树自带功能……

需要注意的是这题极其坑爹 若每次修改都按可持久化的方法插入 也就是说新建节点的话,空间方面会承受不起…因为不会访问当前节点的历史版本,所以为了节省空间,不要每次都新建……主席树的空间需求好可怕……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int INF = 1000000010;
const int SZ = 100010;

int n,m;

int num[SZ];

namespace first{
    int tmp[SZ];
    int a[SZ];
    LL ans = 0;

    void mergesort(int l,int r)
    {
        if(l == r) return ;
        int mid = (l + r) >> 1;
        mergesort(l,mid);   mergesort(mid + 1,r);
        int pl = l,pr = mid + 1,p = l;
        while(pl <= mid || pr <= r)
        {
            if(pr > r || (pl <= mid && a[pl] <= a[pr]))
                tmp[p ++] = a[pl ++];
            else
                tmp[p ++] = a[pr ++],ans += mid - pl + 1;
        }
        for(int i = l;i <= r;i ++)
            a[i] = tmp[i];
    }

    LL get_ans()
    {
        for(int i = 1;i <= n;i ++)
            a[i] = num[i];
        mergesort(1,n);
        return ans;
    }
}

int pos[SZ];

struct segment{
    int l,r;
    int cnt;
}tree[10000000];

int Tcnt = 0;

int rt[SZ];


void insert(int l,int r,int last,int &now,int x,int d)
{
    if(!now) now = ++ Tcnt;
    tree[now] = tree[last];
    tree[now].cnt += d;
    if(l == r) return ;
    int mid = l + r >> 1;
    if(x <= mid) insert(l,mid,tree[last].l,tree[now].l,x,d);
    else insert(mid + 1,r,tree[last].r,tree[now].r,x,d);
}

void change(int pos,int x,int d)
{
    for(int i = pos;i <= n;i += i & -i)
        insert(1,n,rt[i],rt[i],x,d);
}

int tl,tr;
int tml[SZ],tmr[SZ];

int query_min(int l,int r,int x)
{
    int L = 1,R = n;
    int ans = 0;
    while(L != R)
    {
        int mid = (L + R) >> 1;
        if(mid + 1 <= x)
        {
            int suml = 0,sumr = 0;
            for(int i = 1;i <= tl;i ++)  suml += tree[tree[tml[i]].l].cnt;
            for(int i = 1;i <= tr;i ++)  sumr += tree[tree[tmr[i]].l].cnt;
            ans += sumr - suml;
            for(int i = 1;i <= tl;i ++)  tml[i] = tree[tml[i]].r;
            for(int i = 1;i <= tr;i ++)  tmr[i] = tree[tmr[i]].r;
            L = mid + 1;
        }
        else
        {
            for(int i = 1;i <= tl;i ++)  tml[i] = tree[tml[i]].l;
            for(int i = 1;i <= tr;i ++)  tmr[i] = tree[tmr[i]].l;
            R = mid;            
        }
    }
    return ans;
}

int query_max(int l,int r,int x)
{
    int L = 1,R = n;
    int ans = 0;
    while(L != R)
    {
        int mid = (L + R) >> 1;
        if(mid >= x)
        {
            int suml = 0,sumr = 0;
            for(int i = 1;i <= tl;i ++)  suml += tree[tree[tml[i]].r].cnt;
            for(int i = 1;i <= tr;i ++)  sumr += tree[tree[tmr[i]].r].cnt;
            ans += sumr - suml;
            for(int i = 1;i <= tl;i ++)  tml[i] = tree[tml[i]].l;
            for(int i = 1;i <= tr;i ++)  tmr[i] = tree[tmr[i]].l;
            R = mid;
        }
        else
        {
            for(int i = 1;i <= tl;i ++)  tml[i] = tree[tml[i]].r;
            for(int i = 1;i <= tr;i ++)  tmr[i] = tree[tmr[i]].r;
            L = mid + 1;            
        }
    }
    return ans;
}


int ask_min(int l,int r,int x)
{
    tl = 0; tr = 0;
    l --;
    for(int i = l;i > 0;i -= i & -i)
        tml[++ tl] = rt[i];
    for(int i = r;i > 0;i -= i & -i)
        tmr[++ tr] = rt[i];
    return query_min(l,r,x);
}

int ask_max(int l,int r,int x)
{
    tl = 0; tr = 0;
    l --;
    for(int i = l;i > 0;i -= i & -i)
        tml[++ tl] = rt[i];
    for(int i = r;i > 0;i -= i & -i)
        tmr[++ tr] = rt[i];
    return query_max(l,r,x);
}

void scanf(int &n)
{
    n = 0;
    char a = getchar();
    bool flag = 0;
    while(a < '0'|| a > '9') { if(a == '-') flag = 1; a = getchar(); }
    while('0' <= a && a <= '9') { n = n * 10 + a - '0'; a = getchar(); }
    if(flag) n = -n;
}

int main()
{
    scanf(n); scanf(m);
    for(int i = 1;i <= n;i ++)
    {
        scanf(num[i]);
        pos[num[i]] = i;
        change(i,num[i],1);
    }
    LL ans = first :: get_ans();
    for(int i = 1;i <= m;i ++)
    {
        printf("%lld\n",ans);
        int x;
        scanf(x);
        change(pos[x],x,-1);
        int tmp1 = ask_min(pos[x] + 1,n,x),tmp2 = ask_max(1,pos[x] - 1,x);
        ans -= tmp1 + tmp2;
    }
    return 0;
}

你可能感兴趣的:(【bzoj3295】[Cqoi2011]动态逆序对 树状数组套主席树)