POJ2299题解(树状数组)

POJ2299题解

2019-12-28

Powered by Gauss

1.题目传送门:POJ2299

2.理解题意:

做题的时候,第一步也是最重要的就是理解题意。记住这句话。

POJ2299是一道标准的树状数组模板题。题意大致如下:

快速排序是一种非常优秀的排序方式,其精华在于循环比较和swap函数的应用。

先给你一个数N,表示这组数据(没错,这题是多组数据)数的个数,之后的N行,每行一个数Ai

请你输出在快速排序过程中经历的swap函数的次数。

3.算法思路:

树状数组是一种非常高效的数据结构,由于篇幅有限,这里不做讲解,作者将尽快写出一篇树状数组的稿子,敬请谅解。

树状数组的精华在于lowbit函数的使用,为了迎合题目,这里将query函数和update函数做了一些改动。

void update(int x,int k)
{
    int i;
    for(i=x;i<=n;i=i+lowbit(i))
    {
        tree[i]+=k;
    }
}
int query(int x)
{
    int i,sum=0;
    for(i=x;i>0;i=i-lowbit(i))
    {
        sum+=tree[i];
    }
    return sum;
}

我们因为这道题的数据规模非常大,所以要用到一些离散化的思想。

for(i=1;i<=n;i++)
{
     cin>>a[i].value;
     a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(i=1;i<=n;i++)
{
    a[i].pos=i;
}

有了离散化,我们就可以大大降低时间复杂度了。

上面那段代码中,我们用结构体node来实现,包含三个参数,id,pos和value。

struct node
{
  int id,value,pos;
}a[500001];

最后,结合树状数组的计算模板,我们给出最后的AC源代码,用时3610MS:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int tree[500001],n;
struct node
{
  int id,value,pos;
}a[500001];
int lowbit(int x)
{
    return (x&(-x));
}
void update(int x,int k)
{
    int i;
    for(i=x;i<=n;i=i+lowbit(i))
    {
        tree[i]+=k;
    }
}
int query(int x)
{
    int i,sum=0;
    for(i=x;i>0;i=i-lowbit(i))
    {
        sum+=tree[i];
    }
  return sum;
}
int cmp(node a,node b)
{
    return a.value<b.value;
}
int cmp1(node a,node b)
{
    return a.id<b.id;
}
int main()
{
    int i;
    long long sum;
    while(cin>>n && n)
    {
        sum=0;
        memset(tree,0,sizeof(tree));
        for(i=1;i<=n;i++)
        {
            cin>>a[i].value;
            a[i].id=i;
        }
        sort(a+1,a+n+1,cmp);
        for(i=1;i<=n;i++)
        {
            a[i].pos=i;
        }
        sort(a+1,a+n+1,cmp1);
        for(i=1;i<=n;i++)
        {
            sum+=i-1-query(a[i].pos);
            update(a[i].pos,1);
        }
        cout<<sum<<endl;
    }
    return 0;
}

版权声明:知识产权神圣不可侵犯,这篇文章中的部分代码和思想源自:https://blog.csdn.net/weixin_43918531/article/details/87950037

原文地址:https://www.cnblogs.com/Warframe-Gauss/p/12113028.html

时间: 2024-10-31 13:04:02

POJ2299题解(树状数组)的相关文章

poj2299 Ultra-QuickSort 树状数组求逆序数

poj2299 Ultra-QuickSort   树状数组求逆序数 Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 49587   Accepted: 18153 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequenc

luoguP2184 贪婪大陆 题解(树状数组)

P2184 贪婪大陆  题目 其实很容易理解就是询问一段区间内有多少段不同的区间 然后再仔细思索一下会发现: 1.只要一个区间的开头在一个节点i的左边,那么这个区间包含在区间1~i中. 2.只要一个区间的尾部在一个节点j的左边,那么这个区间肯定不属于j之后的所有区间 这时候就不难想到用两个树状数组维护: 第一个:维护节点i之前有多少个区间的开头 第二个:维护节点j之前有多少个区间的结尾 不难证明拿sum[i]-sum[j]得到的就是i~j中间地雷的个数(手动模拟一波就一清二楚了) #includ

poj2299(离散化+树状数组求逆序)

数据范围比较大,先用离散化将数据映射到可控的范围,然后应用树状数组求逆序求解. 总共有N个数,如何判断第i+1个数到最后一个数之间有多少个数小于第i个数呢?不妨假设有一个区间 [1,N],只需要判断区间[i+1,N]之间有多少个数小于第i个数.如果我们把总区间初始化为0,然后把第i个数之前出现过的数都在相应的区间把它的值定为1,那么问题就转换成了[i+1,N]值的总和.再仔细想一下,区间[1,i]的值+区间[i+1,N]的值=区间[1,N]的值(i已经标记为1),所以区间[i+1,N]值的总和等

poj2299(Ultra-QuickSort)树状数组+离散化

题目就是让你求逆序数,用树状数组很简单,不过数据太大,要先进行离散化,将数据范围压缩到1~n以内.还有poj竟然不支持c++11,害得我lambda表达式编译错误. #include <iostream> #include <sstream> #include <fstream> #include <string> #include <map> #include <vector> #include <list> #incl

[CTSC2017]最长上升自序列(伪题解)(树状数组+DP套DP+最小费用最大流+Johnson最短路+Yang_Tableau)

部分分做法很多,但每想出来一个也就多5-10分.正解还不会,下面是各种部分分做法: Subtask 1:k=1 LCS长度最长为1,也就是说不存在j>i和a[j]>a[i]同时成立.显然就是一个LDS,树状数组直接求即可. Subtask 2:k=2 最多两个,也就是可以由两个LCS拼起来,f[i][j]表示第一个LCS以i结尾,第二个以j结尾的方案数,转移显然. Subtask 3:k=2 树状数组优化DP,复杂度由$O(n^3)$降为$O(n^2 \log n)$ Subtask 4,5:

poj--2299(树状数组+离散化)

一.离散化: https://www.cnblogs.com/2018zxy/p/10104393.html 二.逆序数 AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int maxn = 510000; struct Node{ LL data;

【bzoj2789】[Poi2012]Letters 树状数组求逆序对

题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. 输出 一个非负整数,表示最少的交换次数. 样例输入 3 ABC BCA 样例输出 2 题解 树状数组求逆序对 一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中

【树状数组】Bzoj1878[SDOI2009] HH的项链

Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的贝壳?这个问题很难回答...因为项链实在是太长了.于是,他只好求助睿智的你,来解 决这个问题. Input 第一行:一个整数N,表示项链的长度. 第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的

【bzoj4994】[Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组

题目描述 给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数 样例输入 4 3 2 4 4 1 3 2 1 样例输出 3 题解 树状数组 WH说是CDQ分治直接把我整蒙了... 把所有数按照第一次出现位置从小到大排序,然后扫一遍.此时一定是满足$a_j>a_i$的. 那么只需要求出$(a_j,b_j)$中以前出现过的$b_i$的数目.使用树状数组维护即可. 时间复杂度$O(n\log n)$ #include &l