zoukankan      html  css  js  c++  java
  • 【洛谷P6186】[NOI Online #1 提高组] 冒泡排序

    前言

    【题目传送门】
    个人一直觉得用两个树状数组/线段树维护信息的题都很巧妙(因为我想不到),这题正好就是。
    而且本身也有一点思维含量。

    题解

    先从冒泡排序的那个询问入手,考虑一轮排序过后有什么影响。
    直观感受是每一个大值会一路往后走,直到遇到更大的值,而且每一轮都至少排好一个数。但是感觉这都没太大用啊!
    回顾逆序对的统计,是对于每个数看它前面有多少个大于它的数字,再仔细观察就会发现每一轮排序过后,每个数前面比他大的数都只会减少固定的值:一个。
    记录 (f_i) 表示 (i) 位置的数字前面有多少个大于它的数,那么初始逆序对的答案就是 (sum f_i)
    那么 (k) 轮排序之后的答案就是所有大于 (k)(f_i) 之和减去 (k imes) (大于 (k)(f_i) 个数)。
    这两个都可以用权值线段树或者树状数组记录,然而我写的时候分类讨论炸了,还是看了题解才讨论对...

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define FCC fclose(stdin),fclose(stdout)
    const int INF = 0x3f3f3f3f,N = 2e5+10;
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    ll f[N],a[N];
    int n,m;
    struct BIT
    {
    	ll c[N];
    	inline void update(int x,int v)
    	{
    		if(!x) return; 
    		for(int i=x;i<=n;i+=i&-i) c[i]+=v;
    	}
    	inline ll query(int x)
    	{
    		ll ret=0;
    		for(int i=x;i;i-=i&-i) ret+=c[i];
    		return ret;
    	}
    
    }tr1,tr2;
    //tr1求初始逆序对,后来求值域上面的个数,tr2求值域的答案。
    //(上面这句话貌似只有我自己能看懂) 
    void pretreat()
    {
    	for(int i=1;i<=n;i++)	
    	{
    		tr1.update(a[i],1);
    		f[i]=tr1.query(n)-tr1.query(a[i]);
    		//printf("f[%d]=%d
    ",i,f[i]);
    		tr2.update(f[i],f[i]);
    	}
    	memset(tr1.c,0,sizeof(tr1.c)); //tr1回收利用 
    	for(int i=1;i<=n;i++) tr1.update(f[i],1);
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	pretreat();
    	for(int i=1;i<=m;i++)	
    	{
    		int op=read(),x=read();
    		if(op==1)
    		{
    			tr1.update(f[x],-1),tr2.update(f[x],-f[x]);
    			tr1.update(f[x+1],-1),tr2.update(f[x+1],-f[x+1]);
    			swap(f[x],f[x+1]);
    			if(a[x]>a[x+1]) f[x]--;
    			else f[x+1]++;
    			swap(a[x],a[x+1]);
    			tr1.update(f[x],1),tr2.update(f[x],f[x]);
    			tr1.update(f[x+1],1),tr2.update(f[x+1],f[x+1]);
    		}
    		else 
    		{
    			if(x>=n) {puts("0");continue;}
    			int cnt=tr1.query(n)-tr1.query(x);
    			printf("%lld
    ",tr2.query(n)-tr2.query(x)-1ll*cnt*x);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    51nod 1179 最大的最大公约数 (数论)
    POJ 3685 二分套二分
    POJ 3045 贪心
    LIC
    HDU 1029 Ignatius and the Princess IV
    HDU 1024 Max Sum Plus Plus
    HDU 2389 Rain on your Parade
    HDU 2819 Swap
    HDU 1281 棋盘游戏
    HDU 1083 Courses
  • 原文地址:https://www.cnblogs.com/conprour/p/15520126.html
Copyright © 2011-2022 走看看