题目链接: Ultra-QuickSort
第一种解法(线段树)
思路
刚刚学线性代数学到的逆序数,用多重循环果然超时,刚开始的时候完全没有线段树的思路,后来看了别人的思路,发现真的妙啊,开心的飞起来,虽然我后面又因为把小括号写成中括号的问题WA了一晚上。比如说9 1 0 5 4这个序列,我们记录一下他们的序号位置,然后再排个序:
0 | 1 | 4 | 5 | 9 | |
---|---|---|---|---|---|
在原序列中的位置 | 3 | 2 | 5 | 4 | 1 |
开始我们把每个节点的数值都设置为1;
我们从最小数0开始看,他原来的位置是3,说明它前面比它大的有两个数,我们查询从1到(位置-1),也就是1到2,查询这段区间的总和为2;然后我们把这个位置的和-1,再依次往后看次小数。我们把所有查询的数字加起来就是总的逆序数了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=500001;
int addmark[maxn<<2],seqtree[maxn<<2];
struct node{
int value,id;
}a[maxn];
int cmp(node a,node b)
{
return a.value<b.value;
}
void maketree(int node,int begin,int end)
{
if(begin==end)
{
seqtree[node]=1;
return;
}
int mid=(begin+end)/2;
maketree(node<<1,begin,mid);
maketree(node<<1|1,mid+1,end);
seqtree[node]=seqtree[node<<1]+seqtree[node<<1|1];
}
void update(int node,int begin,int end,int pos,int grade)
{
if(pos<begin || pos>end)
return;
if(begin==end && begin==pos)
{
seqtree[node]+=grade;
return;
}
int mid=(begin