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

    题目

    sol:

    考虑一下冒泡排序的过程,从左侧开始,将第一个数(x_1)拿到第一个比它的的位置,同时将这个比它大的数(x_2)拿到下一个比x_2的的位置,这样一直循环下去。

    假设有一次操作,我们将x[i]拿到比它大的位置j上去,那么(i, j)这个区间中的数相当于往前移动的一位,并且逆序对数会减少1。并且我们发现,x[i]的逆序对数一定是0,因为如果不是0,
    那么它就不可能被拿出来。 那么我们可以得到一个结论,经过一轮冒泡排序,第i个位置上的数的逆序对数变为 :

    [c_i = max(c_{i + 1} - 1, 0) ]

    经过k轮冒泡排序,那么答案为:

    [ans = sum_{i >=k + 1} (c_i - k) ]

    可以用两个权值树状数组来维护。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    
    const int N = 2e5 + 100;
    typedef long long LL;
    
    LL tr[N], T[N], c[N], ans;
    int n, q, a[N];
    
    inline int lowbit(int x) {
    	return x & -x; 
    } 
    
    void add(int x, int v) {
    	for(; x <= n + 3; x += lowbit(x))
    		tr[x] += v;
    }
    LL ask(int x) {
    	LL res = 0;
    	for(; x; x -= lowbit(x))
    		res += tr[x];
    	return res;
    }
    void change(int x, int v) {
    	for(; x <= n + 3; x += lowbit(x))
    		T[x] += v;
    }
    LL query(int x) {
    	LL res = 0;
    	for(; x; x -= lowbit(x))
    		res += T[x];
    	return res;
    }
    
    void output(LL* s) {
    	puts("Debug");
    	for(int i = 1; i <= n; i ++)
    	    printf("%lld ", s[i]);
    	puts(""); 
    }
    
    int main()
    {
    //#ifdef LOCAL
    //	freopen("E:\data.in.txt", "r", stdin);
    //#endif
    	scanf("%d%d", &n, &q);
    	for(int i = 1; i <= n; i ++) {
    		scanf("%d", &a[i]);
    		c[i] = ask(n) - ask(a[i]); 
    		add(a[i], 1);
    		if( c[i])  change(c[i], c[i]);
    	}
    	for(int i = 1; i <= n; i ++)    add(i, -1);
    	for(int i = 1; i <= n; i ++)    
    	    if(c[i])  add(c[i], 1);//下标不能为0 
    	
    	while(q --) {
    		int op, x;
    		scanf("%d%d", &op, &x);
    		if( op == 1) {
    			if(c[x])    
    			    change(c[x], -c[x]),  add(c[x], -1);
    			if(c[x + 1])
    			    change(c[x + 1], -c[x + 1]), add(c[x + 1], -1);
    			swap(c[x], c[x + 1]);
    			if( a[x] < a[x + 1]) {
    				c[x + 1] ++;
    				change(c[x + 1], c[x + 1]);
    				add(c[x + 1], 1);
    				if(c[x])    
    			        change(c[x], c[x]),  add(c[x], 1);
    			} else {
    				c[x] --;
    				if(c[x])    
    				    change(c[x], c[x]), add(c[x], 1);
    				if(c[x + 1])
    			        change(c[x + 1], c[x + 1]), add(c[x + 1], 1);
    			}
    			
    			swap(a[x], a[x + 1]);
    		} else {
    			if(x >= n)	{
    				puts("0");
    				continue;
    			}
    			ans = query(n + 1) - query(x);
    			ans -= x * (ask(n + 1) - ask(x)); 
    			printf("%lld
    ", ans);
    		}
    	}
    	return 0;
    } 
    /*
    3 6
    2 1 3
    2 0
    
    */
    
    
  • 相关阅读:
    代码题(22)— 二叉树镜像、相同的树 、对称二叉树
    代码题(26)— 不同路径
    代码题(25)— 最大子序和、最长上升子序列
    Linux 基本命令总结
    C++(五)— 控制保留小数位数
    C++(四)— 字符串、数字翻转3种方法
    代码题(24)— 寻找重复数、数组中重复的数据、找到所有数组中消失的数字
    代码题(23)— 数组中的最长山脉
    【vue】vue +element 搭建项目,将js函数变成vue的函数
    【vue】vue +element 搭建项目,$createElement使用
  • 原文地址:https://www.cnblogs.com/wyy0804/p/13769277.html
Copyright © 2011-2022 走看看