• bzoj 3295: [Cqoi2011]动态逆序对


    Description

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

    题解:
    这题一看上去就是个主席树板子题,但是数据范围可以暴力分块,我就当练习写了个分块,根据n=100000,开block=1000 分块,刚好符合内存和时间要求,我就乱搞了个block=1000,然后最多有100个块,每一个块单独开一个树状数组,然后就像平时求逆序对一样,直接在a[i]对应的位置+1,然后删除就是-1,对于同一个块内,直接暴力搞,不同块也直接枚举每一个块,分别查一次树状数组,然后ans减去这个数的贡献就是当前的答案 复杂度 O(msqrt(n)logn)

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=100005,M=105;
    int gi(){
    	int str=0;char ch=getchar();
    	while(ch>'9' || ch<'0')ch=getchar();
    	while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
    	return str;
    }
    int n,m,a[N],del[N],w[N],bol=1000,bel[N],tot,Tree[M][N],s[M],ed[M];
    bool d[N];int sz[M];
    il void add(int t,int sta,int to){
    	for(RG int i=sta;i<=n;i+=(i&(-i)))Tree[t][i]+=to;
    }
    il int query(int t,int sta){
    	RG int ret=0;
    	for(RG int i=sta;i>=1;i-=(i&(-i)))ret+=Tree[t][i];
    	return ret;
    }
    void work()
    {
    	n=gi();m=gi();int cnt=0,tot=1;s[1]=1;
    	for(int i=1;i<=n;i++){
    		a[i]=gi(),w[a[i]]=i;
    		if(cnt==bol)cnt=0,tot++,s[tot]=i,ed[tot-1]=i-1;bel[i]=tot;cnt++;
    		sz[tot]++;
    	}
    	ed[tot]=n;
    	for(RG int i=1;i<=tot;i++)
    		for(RG int j=s[i];j<=ed[i];j++)
    			add(i,a[j],1);
    	for(int i=1;i<=m;i++)del[i]=gi();
    	ll ans=0;
    	for(RG int i=1;i<=n;i++){
    		ans+=i-1-query(tot+1,a[i]);
    		add(tot+1,a[i],1);
    	}
    
    	RG int t,bl;
    	for(int i=1;i<=m;i++){
    		t=w[del[i]];bl=bel[t];
    		printf("%lld
    ",ans);
    		for(int j=t-1;j>=s[bl];j--)
    			if(!d[j] && a[j]>del[i])ans--;
    		for(int j=t+1;j<=ed[bl];j++)
    			if(!d[j] && a[j]<del[i])ans--;
    		d[t]=true;
    		for(int j=1;j<bl;j++)
    			ans-=sz[j]-query(j,del[i]);
    		for(int j=bl+1;j<=tot;j++)
    			ans-=query(j,del[i]);
    		add(bl,del[i],-1);sz[bl]--;
    	}
    }
    
    int main()
    {
    	freopen("inverse.in","r",stdin);
    	freopen("inverse.out","w",stdout);
    	work();
    	return 0;
    }
    
  • 相关阅读:
    迭代器模式 -- 大话设计模式
    组合模式 -- 大话设计模式
    备忘录模式 -- 大话设计模式
    totalcmd简单教程--help详解
    Listary Primary
    Cygwin Primary
    Google calendar
    极点郑码标点符号
    Totalcmd 简单教程
    Foobar 简单教程
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7420571.html
Copyright © 2020-2023  润新知