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;
    }
    
  • 相关阅读:
    sql 删除表数据并使ID自增重置
    PHP的常用字符串处理
    一个http请求的详细过程
    elasticsearch7.7-postman-json脚本
    elasticsearch7.7入门三-小试牛刀-批量导入json数据
    elasticsearch7.7入门三-小试牛刀
    elasticsearch7.7入门二-安装
    elasticsearch7.7入门一-介绍
    java8新特性七-Date Time API
    java8新特性五-Stream
  • 原文地址:https://www.cnblogs.com/conprour/p/15520126.html
Copyright © 2011-2022 走看看