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;
    }
    
  • 相关阅读:
    Leetcode 92. Reverse Linked List II
    Leetcode 206. Reverse Linked List
    Leetcode 763. Partition Labels
    Leetcode 746. Min Cost Climbing Stairs
    Leetcode 759. Employee Free Time
    Leetcode 763. Partition Labels
    搭建数据仓库第09篇:物理建模
    Python进阶篇:Socket多线程
    Python进阶篇:文件系统的操作
    搭建数据仓库第08篇:逻辑建模–5–维度建模核心之一致性维度2
  • 原文地址:https://www.cnblogs.com/conprour/p/15520126.html
Copyright © 2011-2022 走看看