UVA11990 ``Dynamic'' Inversion (树状数组套平衡树)

来源:互联网 发布:相思相见知何日 编辑:程序博客网 时间:2024/04/30 21:39

``Dynamic'' Inversion

3000ms
131072KB
This problem will be judged on UVA. Original ID: 11990
64-bit integer IO format: %lld      Java class name: Main
Prev Submit Status Statistics Discuss Next
Font Size:  

[PDF Link]

Problem D

"Dynamic" Inversion

You are given a permutation {1,2,3,...,n}. Remove m of them one by one, and output the number of inversion pairs before each removal. The number of inversion pairs of an array A is the number of ordered pairs (i,j) such that i < j and A[i] > A[j].

Input

The input contains several test cases. The first line of each case contains two integers n and m (1<=n<=200,000, 1<=m<=100,000). After that, n lines follow, representing the initial permutation. Then m lines follow, representing the removed integers, in the order of the removals. No integer will be removed twice. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.

Output

For each removal, output the number of inversion pairs before it.

Sample Input

5 4153425142

Output for the Sample Input

5221

Explanation

(1,5,3,4,2)->(1,3,4,2)->(3,4,2)->(3,2)->(3)


Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Yi Chen, Dun Liang
Note: Please make sure to test your program with the gift I/O files before submitting!
Prev Submit Status Statistics Discuss Next
给你一个1到n的排列,进行m次删除操作,输出每次删除之前的逆序对数,静态逆序对可以用归并排序或者树状数组来求,动态的可以用树状数组套平衡树来求,具体来说,就是树状数组的每个节点是一颗平衡树,第x个节点保存x,x-1,x-2...,x-lowbit(x)+1的所有值(建成平衡树),假设要删除的数是x[i]在原排列中的位置是pos[i],我们只需要知道1到pos[i-1]中有多少个数比x[i]大和pos[i+1]到结尾有多少个数比x[i]小,就能知道逆序对减少了多少(已经删除的点直接忽略掉).那么我们可以通过在pos[i],pos[i]-lowbit(pos[i]),pos[i]-lowbit(pos[i]) - lowbit(pos[i]-lowbit(pos[i]))...中查找有多少个数比小于等于x,记为t2,则1到pos[i]中节点总数减t2就得到前缀比x[i]大的,小于等于x的总数(可以通过树状数组查询 ask(c,val) )-t2就是后缀里比x小的,然后更新pos[i],pos[i]+lowbit(pos[i]).....这些平衡树,给被删除的节点打上标记(--siz即可),同时在原树状数组里x[i]位置上加上-1.


#include <bits/stdc++.h>int lowbit(int x) {return x & -x;}using namespace std;typedef long long ll;const int N = 2e5 + 10;const int M = 4e6 + 10;int tot;struct Splay {    int fa,key,siz;    int ch[2];    Splay() = default;    Splay(int fa,int key):fa(fa),key(key),siz(1){        ch[0] = ch[1] = 0;    }}Node[M];int newNode(int fa,int key){    int rt = ++tot;    Node[rt] = Splay(fa,key);    return rt;}int built(vector<int>&v,int fa,int l,int r){    int mid = (l + r) >> 1;    int rt = newNode(fa,v[mid-1]);    Splay & t = Node[rt];    if(mid > l) t.ch[0] = built(v,rt,l,mid-1);    if(mid < r) t.ch[1] = built(v,rt,mid+1,r);    t.siz += Node[t.ch[0]].siz + Node[t.ch[1]].siz;    return rt;}int ask(int rt,int x)///询问rt为根的子树里有多少不大于x的节点{    if(!rt)return 0;    Splay & t = Node[rt];    if(t.key == x) {        return Node[t.ch[0]].siz+1;    }    bool flag = (t.siz - (Node[t.ch[0]].siz + Node[t.ch[1]].siz));///是否没被删除    if(t.key < x) return Node[t.ch[0]].siz + flag + ask(t.ch[1],x);    return ask(t.ch[0],x);}void remove(int rt,int x){    Splay & t = Node[rt];    --t.siz;    if(t.key==x)return;    remove(t.ch[t.key < x],x);}int n,m;int root[N],pos[N];vector<int>vec[N];int c[N];void add(int *T,int x,int d){    for(;x <= n; x += (x&-x)) {        T[x] += d;    }}int ask(int *T,int x){    int ans = 0;    for(;x > 0; x -= (x&-x)) {        ans += T[x];    }    return ans;}ll cnt;int init(){    if(scanf("%d%d",&n,&m)!=2) return 0;    memset(c,0,sizeof(int)*(n+1));    for(int i = 0; i <= n; ++i) vec[i].clear();    tot = cnt = 0;    Node[0].siz = 0;    for(int i = 1; i <= n; ++i) {        int x;        scanf("%d",&x);        cnt += (i-1)-ask(c,x);        add(c,x,1);        pos[x] = i;        for(int j = i; j <= n; j += (j&-j)) {            vec[j].push_back(x);        }    }    for(int i = 1; i <= n; ++i) {///可以通过打标记将删除变成静态的,直接按照完全二叉树来建树即可        sort(vec[i].begin(),vec[i].end());        root[i] = built(vec[i],0,1,vec[i].size());    }    return 1;}void change(int x,int val){    int t1 = 0,t2 = 0;    for(; x > 0; x -= (x&-x)) {        int t = ask(root[x],val); //查询root[x]里有多少个数小于等于val        t2 += t;        t1 += Node[root[x]].siz - t;//大于val的个数    }    t2 = ask(c,val) - t2;//后缀里小于val的个数    add(c,val,-1);//在val位置加-1    cnt -= (t1+t2);//删除之后对逆序对的影响    x = pos[val];    for( ;x <= n; x += (x&-x)) remove(root[x],val);//在受影响的平衡树中删除节点}int main(){    while(init()) {        for(int i = 0; i < m; ++i) {            int x;scanf("%d",&x);            printf("%lld\n",cnt);            change(pos[x],x);        }    }    return 0;}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果8蜂窝上网慢怎么办 苹果6s4g网速慢怎么办 苹果7上网速度慢怎么办 银行转账到别人账户怎么办 银行转账转错账户怎么办 人已故欠的公款怎么办 论文抄了表格数据怎么办 电子转账转错了怎么办 苹果手机付款方式有问题怎么办 合同中付款方式错怎么办? 优步付款方式无效怎么办 工程付款方式变更没有合同怎么办 银行账号被锁了怎么办? 街电押金退不了怎么办 佣金宝账号忘了怎么办 如果汇款汇错了怎么办 手机汇款汇错了怎么办 汇款时少了数字怎么办 打过流脑后发烧怎么办 甲醛公司除完后怎么办 发票系统导出的xml 怎么办 新买的书包味道太大怎么办 alt+a截图热键冲突怎么办 白背心领发黄了怎么办 房屋装修后出现质量问题怎么办 华为p9手机音量小怎么办 华为畅享8玩游戏卡怎么办 华为畅享7玩游戏卡怎么办 华为p9升级以后屏幕失灵怎么办 荣耀9青春版玩游戏卡怎么办 华为p9屏幕不亮了怎么办 华为p9入水黑屏怎么办 农信密码忘记了怎么办 小米4g信号差怎么办 手机的调频调制器坏了怎么办 调制解调器的灯一直闪怎么办 691宽带用户名和密码无效怎么办 房间里有狐臭味怎么办 吃冰冻水果胃特别痛怎么办 小米5s屏幕闪烁怎么办 系统重装重启了怎么办