zoukankan      html  css  js  c++  java
  • BZOJ3295 [Cqoi2011]动态逆序对 分治 树状数组

    原文链接http://www.cnblogs.com/zhouzhendong/p/8678185.html

    题目传送门 - BZOJ3295

    题意

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

    题解

      我们首先把原题目转化成依次加入数字求总逆序对个数。

      假设某一个数字被加入的时间为$t$,他的位置为$id$,它的值为$v$。

      则存在两种情况,使得$i$能更新$j$。

      $Situation 1:$

      $t_i<t_j,id_i<id_j,v_i>v_j$

      $Situation 2:$

      $t_i<t_j,id_i>id_j,v_i<v_j$

      于是机智的你是不是发现CDQ分治一下就秒掉了???

      (其实这题如果用带修改的主席树或者树套树貌似脑子都不用动…………)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    struct Node{
    	int id,v,t,res;
    }a[N],b[N];
    int n,m,pos[N],tree[N];
    LL res[N];
    int lowbit(int x){
    	return x&-x;
    }
    void add(int x,int y){
    	for (;x<=n;x+=lowbit(x))
    		tree[x]+=y;
    }
    int sum(int x){
    	int ans=0;
    	for (;x>0;x-=lowbit(x))
    		ans+=tree[x];
    	return ans;
    }
    void CDQ(int L,int R){
    	if (L==R)
    		return;
    	int mid=(L+R)>>1;
    	for (int i=L,l=L,r=mid+1;i<=R;i++)
    		if (a[i].t<=mid)
    			b[l++]=a[i];
    		else
    			b[r++]=a[i];
    	for (int i=L;i<=R;i++)
    		a[i]=b[i];
    	int j=L;
    	for (int i=mid+1;i<=R;i++){
    		while (j<=mid&&a[j].id<a[i].id)
    			add(n+1-a[j].v,1),j++;
    		a[i].res+=sum(n+1-a[i].v);
    	}
    	for (int i=L;i<j;i++)
    		add(n+1-a[i].v,-1);
    	j=mid;
    	for (int i=R;i>mid;i--){
    		while (j>=L&&a[j].id>a[i].id)
    			add(a[j].v,1),j--;
    		a[i].res+=sum(a[i].v);
    	}
    	for (int i=mid;i>j;i--)
    		add(a[i].v,-1);
    	CDQ(L,mid),CDQ(mid+1,R);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++){
    		scanf("%d",&a[i].v);
    		a[i].id=pos[a[i].v]=i;
    		a[i].t=a[i].res=0;
    	}
    	for (int i=1,x;i<=m;i++){
    		scanf("%d",&x);
    		a[pos[x]].t=n-i+1;
    	}
    	for (int i=1,t=n-m;i<=n;i++)
    		if (!a[i].t)
    			a[i].t=t--;
    	memset(tree,0,sizeof tree);
    	CDQ(1,n);
    	memset(res,0,sizeof res);
    	for (int i=1;i<=n;i++)
    		res[a[i].t]+=a[i].res;
    	for (int i=2;i<=n;i++)
    		res[i]+=res[i-1];
    	for (int i=n;i>n-m;i--)
    		printf("%lld
    ",res[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    【BZOJ4915】简单的数字题(数学)
    【BZOJ2140】稳定婚姻(匈牙利算法板子题)
    【BZOJ2739】最远点(决策单调性)
    【AT3526】[ARC082C] ConvexScore(贡献转化+容斥)
    【CF1264D2】Beautiful Bracket Sequence(组合数学)
    【洛谷2561】[AHOI2002] 黑白瓷砖(Polya定理)
    【洛谷3511】[POI2010] MOS-Bridges(混合图欧拉回路)
    【洛谷4226】避难所(构造)
    【洛谷7453】[THUSCH2017] 大魔法师(线段树+矩乘)
    【洛谷3207】[HNOI2010] 物品调度(置换问题)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ3295.html
Copyright © 2011-2022 走看看