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

    传送门


    不得不说,NOI Online的质量确实不错,有一定的思维难度,而且比较新颖。
    怎么说呢,这题我差点就搞出来了。


    这题刚开始我一点思路都没有,后来经过大量的手模后发现了一些规律,知道这个规律后,题目的一大半就解决了。
    记在前(i)个数中,比(a_i)大的数的个数为(b_i),那么每一轮冒泡排序后,所有(b_i)都会-1,直到(b_i)等于0.
    说白了,就是让求

    [sum_{i=1}^{n} max {b_i - x, 0 } ]

    这个结论的证明,可以这么想:如果在(a_i)前面有比(a_i)大的,那么这其中最大的数一定会在冒泡排序中和(a_i)交换,那么(b_i)就少了1,而一轮冒泡排序中能移动一个比(a_i)大的数,所以只会是减1,而不是变成其他的值。
    那这东西怎么求呢?我就卡在了这里,气死了。


    其实我们只要维护一个权值线段树(树状数组),每一次求大于(x)(b_i)个数及其值的和就行了……
    结果我维护了一个序列线段树,然后用最大最小值一顿乱搞剪枝,拿了60分……唉。


    询问到这就完事了,至于修改,也很简单。
    因为只是相邻的两个数交换,所以只影响(b_i)(b_{i+1})
    如果(a_i < a_{i+1}),那么(b'_i = b_{i+1}, b'_{i+1} = b_i+1)
    如果(a_i > a_{i+1}),那么(b'_i = b_{i+1}-1, b'_{i+1}=b_i)
    在树状数组上单点修改即可。


    上代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<queue>
    #include<assert.h>
    #include<ctime>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 2e5 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen("ha2.in", "r", stdin);
    	freopen("ha.out", "w", stdout);
    #endif
    }
    
    int n, m, a[maxn], b[maxn];
    
    int c[maxn];
    In int lowbit(int x) {return x & -x;}
    In void A(int x)
    {
    	for(; x <= n; x += lowbit(x)) c[x]++;
    }
    In int Q(int x)
    {
    	int ret = 0;
    	for(; x; x -= lowbit(x)) ret += c[x];
    	return ret;
    }
    
    ll c2[maxn], cnum[maxn];
    In void update(int x, int d)
    {
    	ll tp = x;
    	for(int i = n - x + 1; i <= n + 1; i += lowbit(i)) c2[i] += tp * d, cnum[i] += d;
    }
    In ll query(int x)
    {
    	if(x >= n) return 0;
    	ll sum = 0, num = 0;
    	for(int i = n - x + 1; i; i -= lowbit(i)) sum += c2[i], num += cnum[i];
    	return sum - num * x;
    }
    
    int main()
    {
    //	MYFILE();
    	n = read(), m = read();
    	for(int i = 1; i <= n; ++i) a[i] = read();
    	for(int i = 1; i <= n; ++i)
    	{
    		b[i] = Q(n - a[i] + 1);
    		A(n - a[i] + 1);
    	}
    	for(int i = 1; i <= n; ++i) update(b[i], 1);
    	for(int i = 1; i <= m; ++i)
    	{
    		int op = read(), x = read();
    		if(op == 1)
    		{
    			int tp1 = b[x], tp2 = b[x + 1];
    			if(a[x] < a[x + 1]) 
    			{
    				b[x] = tp2, b[x + 1] = tp1 + 1;
    				update(tp1, -1), update(tp1 + 1, 1);
    			}
    			else
    			{
    				b[x] = tp2 - 1, b[x + 1] = tp1;
    				update(tp2, -1), update(tp2 - 1, 1);
    			}
    			swap(a[x], a[x + 1]);
    		}
    		else write(query(x)), enter;
    	}
    	return 0;
    }
    
  • 相关阅读:
    文件遍历
    小记——LocalFree与指针
    小记——遍历文件2
    数据库索引
    easyui验证
    JDBC事务
    ajax登录跳转实现
    dom解析xml
    kindeditor使用
    log4j的配置
  • 原文地址:https://www.cnblogs.com/mrclr/p/13926556.html
Copyright © 2011-2022 走看看