UVA-11990 动态逆序对




题目链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3141


题目大意:

给出一个1-n的排列A,要求按照某种顺序删除一些数(其他数顺序不变),输出每次删除之前逆序对的数目。


解题思路:

动态逆序对,在线的话用块状数组、树套树等高级数据结构解决,然此题可离线,于是可用cdq分治这种淫技奇巧代替。

先用树状数组求出序列原本的逆序对数,去掉某一个数就要减去前面比它大的数的个数以及后面比它小的数的个数,但是去掉一个数后会对其后面的操作产生影响,所以需要计算每次去掉一个数之前去掉的数中,在该数前比该数大的以及在该数后比该数小的,这样操作间构成了一种三维的偏序关系,cdq分治解之。


AC代码:

import java.util.*;

public class Main {
	static int n,m;
	static long ans;
	static int[] aa=new int[200005];
	static int[] bb=new int[200005];
	static int[] cc=new int[100005];
	static int[] dd=new int[100005];
	static int[] mm=new int[200005];
	static int[] bit=new int[200005];
	static Pair[] pp=new Pair[100005];
	static void add(int i,int x)
	{
		for(;i<=n;i+=i&-i)
			bit[i]+=x;
	}
	static int sum(int i)
	{
		int res=0;
		for(;i>0;i-=i&-i)
			res+=bit[i];
		return res;
	}
	static void cdq(int l,int r)
	{
		if(l==r) return;
		int mid=(l+r)/2;
		cdq(l,mid);
		for(int i=l;i<=r;i++)
			pp[i]=new Pair(cc[i],mm[cc[i]],i);
		work(l,r);
		for(int i=l;i<=r;i++)
			pp[i]=new Pair(mm[cc[i]],cc[i],i);
		work(l,r);
		cdq(mid+1,r);
	}
	static void work(int l,int r)
	{
		int mid=(l+r)/2;
		Arrays.sort(pp,l,r+1);
		for(int i=l;i<=r;i++)
		{
			if(pp[i].z<=mid)
				add(pp[i].y,1);
			else
				dd[pp[i].z]+=sum(pp[i].y);
		}
		for(int i=l;i<=r;i++)
			if(pp[i].z<=mid) add(pp[i].y,-1);
	}
	static class Pair implements Comparable<Pair>
	{
		int x,y,z;
		Pair(int a,int b,int c)
		{
			x=a;y=b;z=c;
		}
		public int compareTo(Pair p) {
			return p.x-x;
		}
	}

	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		while(in.hasNext())
		{
			n=in.nextInt();m=in.nextInt();
			for(int i=1;i<=n;i++)
			{
				aa[i]=in.nextInt();
				mm[aa[i]]=i;
			}
			ans=0;
			for(int i=n;i>0;i--)
			{
				bb[i]=sum(aa[i]);
				ans+=bb[i];
				bb[i]+=i+bb[i]-aa[i];
				add(aa[i],1);
			}
			Arrays.fill(bit,0);
			for(int i=1;i<=m;i++)
				cc[i]=in.nextInt();
			Arrays.fill(dd,0);
			cdq(1,m);
			for(int i=1;i<=m;i++)
			{
				System.out.println(ans);
				ans-=bb[mm[cc[i]]]-dd[i];
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值