• BZOJ2141排队——树状数组套权值线段树(带修改的主席树)


    题目描述

    排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家
    乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍
    高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿
    园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿
    姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。

    输入

    第一行为一个正整数n,表示小朋友的数量;
    第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;
    第三行为一个正整数m,表示交换操作的次数;
    以下m行每行包含两个正整数ai和bi,表示交换位置ai与位置bi的小朋友。
    1≤m≤2*10^3,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。

    输出

    输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。

    样例输入

    【样例输入】
    3
    130 150 140
    2
    2 3
    1 3

    样例输出

    1
    0
    3
    【样例说明】
    未进行任何操作时,(2,3)满足条件;
    操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
    操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)
     
      题目大意是求每次交换两个数后的逆序对数。最开始没修改时直接用树状数组求逆序对数就好了。因为逆序对数就是考虑每个数后面比它小的数有多少个,所以每次交换两个数i,j对这两个数与j后面的数产生的逆序对数没有影响,只对i,j中间的数与两个数产生的逆序对数有影响。考虑i,交换之后,i与i,j之间比i小的数产生的逆序对数消失了,但多了i,j之间比i大的数与i的逆序对数,j也是同样道理。所以只要每次求i,j之间比i或j小的和大的数有多少,用主席树维护就好了,但因为每次交换时会修改,因此要用树状数组套权值线段树,也就是带修改的主席树。最后要注意i,j两个数产生的逆序对数的增减。
    #include<set>
    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    int n,m;
    int x,y;
    int tot;
    int cnt;
    int ans;
    int s[20010];
    int t[20010];
    int a[20010];
    int b[20010];
    int v[20010];
    int root[20010];
    int ls[10000010];
    int rs[10000010];
    int sum[10000010];
    void add(int x)
    {
        for(int i=x;i<=tot;i+=i&-i)
        {
            v[i]++;
        }
    }
    int ask(int x)
    {
        int res=0;
        for(int i=x;i;i-=i&-i)
        {
            res+=v[i];
        }
        return res;
    }
    void change(int &rt,int l,int r,int k,int v)
    {
        if(!rt)
        {
            rt=++cnt;
        }
        if(l==r)
        {
            sum[rt]+=v;
            return ;
        }
        sum[rt]+=v;
        int mid=(l+r)>>1;
        if(k<=mid)
        {
            change(ls[rt],l,mid,k,v);
        }
        else
        {
            change(rs[rt],mid+1,r,k,v);
        }
    }
    int query_min(int l,int r,int k)
    {
        int res=0;
        if(l==r)
        {
            return res;
        }
        int mid=(l+r)>>1;
        if(k<=mid)
        {
            for(int i=1;i<=s[0];i++)
            {
                s[i]=ls[s[i]];
            }
            for(int i=1;i<=t[0];i++)
            {
                t[i]=ls[t[i]];
            }
            return query_min(l,mid,k);
        }
        else
        {
            for(int i=1;i<=s[0];i++)
            {
                res+=sum[ls[s[i]]];
                s[i]=rs[s[i]];
            }
            for(int i=1;i<=t[0];i++)
            {
                res-=sum[ls[t[i]]];
                t[i]=rs[t[i]];
            }
            return res+query_min(mid+1,r,k);
        }
    }
    int query_max(int l,int r,int k)
    {
        int res=0;
        if(l==r)
        {
            return res;
        }
        int mid=(l+r)>>1;
        if(k<=mid)
        {
            for(int i=1;i<=s[0];i++)
            {
                res+=sum[rs[s[i]]];
                s[i]=ls[s[i]];
            }
            for(int i=1;i<=t[0];i++)
            {
                res-=sum[rs[t[i]]];
                t[i]=ls[t[i]];
            }
            return res+query_max(l,mid,k);
        }
        else
        {
            for(int i=1;i<=s[0];i++)
            {
                s[i]=rs[s[i]];
            }
            for(int i=1;i<=t[0];i++)
            {
                t[i]=rs[t[i]];
            }
            return query_max(mid+1,r,k);
        }
    }
    void updata(int x,int k,int v)
    {
        for(int i=x;i<=n;i+=i&-i)
        {
            change(root[i],1,tot,k,v);
        }
    }
    int find_max(int l,int r,int k)
    {
        s[0]=t[0]=0;
        for(int i=r;i;i-=i&-i)
        {
            s[++s[0]]=root[i];
        }
        for(int i=l;i;i-=i&-i)
        {
            t[++t[0]]=root[i];
        }
        return query_max(1,tot,k);
    }
    int find_min(int l,int r,int k)
    {
        s[0]=t[0]=0;
        for(int i=r;i;i-=i&-i)
        {
            s[++s[0]]=root[i];
        }
        for(int i=l;i;i-=i&-i)
        {
            t[++t[0]]=root[i];
        }
        return query_min(1,tot,k);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+1+n);
        tot=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
            ans+=ask(tot)-ask(a[i]);
            add(a[i]);
            updata(i,a[i],1);
        }
        printf("%d
    ",ans);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            ans+=find_min(x,y-1,a[y]);
            ans-=find_max(x,y-1,a[y]);
            ans-=find_min(x,y-1,a[x]);
            ans+=find_max(x,y-1,a[x]);
            updata(x,a[x],-1);
            updata(y,a[y],-1);
            swap(a[x],a[y]);
            updata(x,a[x],1);
            updata(y,a[y],1);
            if(a[x]>a[y])
            {
                ans++;
            }
            else if(a[x]<a[y])
            {
                ans--;
            }
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    InnoDB存储引擎介绍-(2)redo和undo学习
    InnoDB存储引擎介绍-(1)InnoDB存储引擎结构
    MySQL共享表空间概念
    MySQL压力测试(1)-mysqlslap
    MySQL5.6复制技术(4)-MySQL主从复制过滤参数
    MySQL5.6复制技术(3)-MySQL主从复制线程状态转变
    MySQL5.6复制技术(2)-主从部署以及半同步配置详细过程
    vue 子组件 $emit方法 调用父组件方法
    es聚合后排序
    java比较两个小数的大小
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9538881.html
Copyright © 2020-2023  润新知