zoukankan      html  css  js  c++  java
  • Luogu-1975 [国家集训队]排队

    Luogu-1975 [国家集训队]排队

    题面

    Luogu-1975

    题解

    题意:给出一个长度为n的数列以及m个交换两个数的操作,问每次操作后逆序对数量

    时间,下标和数的大小三维偏序,,,把交换操作看成是减去两个数再加上两个数,套板子就好了

    发现这种计数类型的CDQ一般有两种写法:

    • 按a排序,CDQ内先递归左右两边让b有序后扫一遍用左边更新右边

    • 按b排序,CDQ内先按照a与mid的关系分为两部分,用前面更新后面,然后递归两边

    感觉应该都差不多,但有些题目用两种方式写也有一些优劣之分,比如这道题,用第二种方式感觉就特别的好写。。。

    代码

    #include<map>
    #include<queue>
    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<bitset>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    inline char gc(){
    //static char buf[100000],*p1,*p2;
    //return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
        return getchar();
    }
    inline int read(){
        int ans=0,fh=1;
        char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') fh=-1; ch=gc();}
        while(ch>='0'&&ch<='9')	ans=(ans<<1)+(ans<<3)+ch-'0',ch=gc();
        return ans*fh;
    }
    const int maxn=3e6+100;
    struct node{
        int tim,a,b,ms,bh;
    }c[maxn],tmp[maxn];
    int n,m,b[maxn],cr[maxn],tre[maxn],cl,tot,qtot,d[maxn];
    ll ans[maxn];
    map<int,int>bh;
    bool cmp(node x,node y){return x.a<y.a||(x.a==y.a&&x.tim<y.tim);}
    void revise(int x,int z){
        for(int i=x;i<maxn;i+=i&(-i))
            if(cr[i]==cl) tre[i]+=z;
            else cr[i]=cl,tre[i]=z;
    }
    int query(int x,int Ans=0){
        for(int i=x;i;i-=i&(-i))
            if(cr[i]==cl) Ans+=tre[i];
        return Ans;
    }
    void cdq(int l,int r){
        if(l==r) return;
        int mid=l+r>>1;cl++;
        for(int i=l;i<=r;i++)
            if(c[i].tim<=mid) revise(c[i].b,c[i].ms);
            else ans[c[i].bh]+=c[i].ms*(query(maxn-1)-query(c[i].b));
        cl++;
        for(int i=r;i>=l;i--)
            if(c[i].tim<=mid) revise(c[i].b,c[i].ms);
            else ans[c[i].bh]+=c[i].ms*query(c[i].b-1);
        int lc=l-1,rc=mid;
        for(int i=l;i<=r;i++)
            if(c[i].tim<=mid) tmp[++lc]=c[i];
            else tmp[++rc]=c[i];
        for(int i=l;i<=r;i++) c[i]=tmp[i];
        cdq(l,mid),cdq(mid+1,r);
    }
    int main(){
    //	freopen("1975.in","r",stdin);
        n=read();int x,y;
        for(int i=1;i<=n;i++){
            b[i]=d[i]=x=read();
            c[i]=(node){i,i,x,1,0};
        }
        sort(b+1,b+n+1);b[0]=-1;
        for(int i=1;i<=n;i++)
            if(b[i]!=b[i-1]) bh[b[i]]=++tot;
        for(int i=1;i<=n;i++)
            c[i].b=d[i]=bh[c[i].b];
        m=read();
        for(int i=1;i<=m;i++){
            x=read(),y=read(),++qtot;
            c[++n]=(node){n,x,d[y],1,qtot};
            c[++n]=(node){n,y,d[x],1,qtot};
            c[++n]=(node){n,x,d[x],-1,qtot};
            c[++n]=(node){n,y,d[y],-1,qtot};
            swap(d[x],d[y]);
        }
        sort(c+1,c+n+1,cmp);
        cdq(1,n);
        for(int i=1;i<=qtot;i++) ans[i]+=ans[i-1];
        for(int i=0;i<=qtot;i++) printf("%lld
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    jquery中$.get()提交和$.post()提交有区别吗?
    数据库连接池的原理。为什么要使用连接池。
    execute,executeQuery,executeUpdate的区别是什么?
    数据库的三级模式与二级映像
    KMP算法(超容易理解的next数组求法)
    软件危机(含通俗理解帮助记忆)
    O(1)复杂度求一个栈的最小值
    操作系统进程状态模型
    判断单链表是否有环,如果有环则找到其环的入口
    两个单链表判断是否相交
  • 原文地址:https://www.cnblogs.com/nianheng/p/10181858.html
Copyright © 2011-2022 走看看