题目如下所示:
当然,第一个想法是两个for,课后作业给的结果是有一个样例没通过(超时)。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
using namespace std;
int main()
{
int count[100100];
memset(count,0,sizeof(count));
int n,j;
int nums[100100];
scanf("%d",&n);
for(int t=0;t<n;t++)
{
scanf("%d",&nums[t]);
}
for(int i=0;i<n;i++)
{
int temp=nums[i];
for(j=i;j<n;j++)
{//cout<<temp<<" "<<nums[j]<<endl;
if(nums[j]<temp)
count[i]++;
}
}
for(int p=0;p<n;p++)
{
cout<<count[p]<<" ";
}
return 0;
}
之后同学建议了使用线段树。
先介绍两个基本的知识点,是为了离散化。
关于lower_bound和upper_bound
共同点
函数组成:(https://blog.csdn.net/Baiyi_destroyer/article/details/81174695)
一个数组元素的地址(或者数组名来表示这个数组的首地址,用来表示这个数组的开头比较的元素的地址,不一定要是首地址,只是用于比较的“首”地址)+ 一个数组元素的地址(对应的这个数组里边任意一个元素的地址,表示这个二分里边的比较的”结尾’地址)+ 你要二分查找的那个数。
例如:
lower_bound(r[x].begin(),r[x].end(),l)
upper_bound(r[x].begin(),r[x].end(),R)
区别
lower_bound与upper_bound的返回值是不同的
lower_bound
返回第一个大于等于x的数的地址
例如数组 1 1 1 3 5
而需要找的那个数是2,怎么返回呢,
就是返回那个第一个大于 2 的数的地址,就是返回3的位置,那么再有一组数据就是5个数1 1 1 3 5,还是需要找寻2,那么该返回什么呢?就是第一个3的地址.
upper_bound
返回第一个大于x的数的地址
也就是说如果在5个数 1 , 1, 2 , 2 , 4 ,里边寻找3,那么就会返回4的地址
代码
lower_bound
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k,n=10;
int a[10]={1,1,1,3,3,5,5,5,5,6};
int main()
{
for(int i=0;i<n;i++)cout<<a[i]<<" ";
cout<<endl;
while(scanf("%d",&k))
{
cout<<k<<"的第一个大于等于它的位置在"<<((lower_bound(a,a+n,k))-a)+1<<endl;
}
}
C++的unique函数
unique是STL中很实用的函数之一,需要#include<iostream>,下面来简单介绍一下它的作用。
unique的作用是“去掉”容器中相邻元素的重复元素,这里去掉要加一个引号,为什么呢,是因为它实质上是一个伪去除,它会把重复的元素添加到容器末尾,而返回值是去重之后的尾地址(是地址!!),举个例子:
int num[10]={1,1,2,2,2,3,4,5,5,5};
int ans=unique(num,num+10)-num;
第一种离散化。(包含重复元素,推荐使用)
我们在处理数组问题时,如需要求逆序数,然而数据给的又特别大,此时我们就可以用数组的离散处理来解决了。
当数的范围比较大时需要进行离散化,即先排个序,再重新编号。如a[] = {10000000, 10, 2000, 20, 300},那么离散化后a[] = {5,
1, 4, 2, 3}。
const int maxn=1e5+10;
int a[maxn], t[maxn];
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",a[i]),t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+1+n)-t-1;//m为不重复的元素的个数
for(int i=1; i<=n; i++)
a[i]=lower_bound(t+1,t+1+m,a[i])-t;
第二种离散化,使用结构体实现
#include<cstdio>
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=500000+1000;
int c[MAXN];
struct node
{
int v;
int index;
bool operator <(const node& b)const
{
return v<b.v;
}
}nodes[MAXN];
int b[MAXN];//将初始数组重新赋值后 相对大小不变的新数组
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&nodes[i].v);
nodes[i].index=i;
}
sort(nodes+1,nodes+n+1);
memset(b,0,sizeof(b));
b[nodes[1].index]=1;
for(int i=2;i<=n;i++)
{
if(nodes[i].v==nodes[i-1].v)
b[ nodes[i].index ]=b[ nodes[i-1].index ];
else
b[ nodes[i].index ]=i;
}
for(int i=1;i<=n;i++)
cout<<b[i]<<endl;
}
然后是线段树的学习。。。。
自己写了一个。。然后测试结果全部是超内存。
#include<cstdio>
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int a[maxn], t[maxn];
int n;
int llMax,llMin;
struct node
{
int count;
int l;//区间左端点
int r;//区间右端点
struct node* left;
struct node* right;
node(int start,int end)
{
count=0;
l=start;
r=end;
left=NULL;
right=NULL;
}
};
void fun()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]),
t[i]=a[i];
}
sort(t+1,t+n+1);
llMin=1;
int m=unique(t+1,t+1+n)-t-1;//m为不重复的元素的个数
llMax=m;
for(int p=1; p<=n; p++)
a[p]=lower_bound(t+1,t+1+m,a[p])-t;
}
node* add(int start,int end)
{
node* root = new node(start,end);
if( start == end)
return root;
root->left = add(start , (start + end)/2);
root->right = add((start + end)/2 + 1 , end);
return root;
}
int query(node* p,int num)
{
p->count++;
if(p->left==NULL && p->right==NULL)
return 0;
if( num <= (p->l+p->r)/2 )
return query(p->left,num);
else
return query(p->right,num)+p->left->count;
}
int main()
{
struct node * p;
int i;
//数据先离散化
fun();
//构造线段树
p=add(llMin,llMax);
int k=0,temp[1010];
for(i=n; i>0; i--)
temp[k++]=query(p,a[i]);
for(i=k-1;i>=0;i--)
cout<<temp[i]<<" ";
return 0;
}
随后的想法是,使用数组进行构建线段树。。使用结构体都很容易超内存。
结果老是超内存,,只好先试试1010大小的数组了。结果是10个样例过了3。。。各种错,等待解决。。。
#include<cstdio>
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010;
int a[maxn], t[maxn];
int n;
int llMax,llMin;
void fun()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]),
t[i]=a[i];
}
sort(t+1,t+n+1);
llMin=1;
int m=unique(t+1,t+1+n)-t-1;//m为不重复的元素的个数
llMax=m;
for(int p=1; p<=n; p++)
a[p]=lower_bound(t+1,t+1+m,a[p])-t;
}
int add(int root,int start,int end,int num)
{
// cout<<start<<" "<<end<<endl;
t[root]++;
int mid=(end+start)/2;
if( start == end)
return 0;
else
{
if(num<=mid)
return add(root*2,start,(start + end)/2,num);
else
return t[root*2]+add(root*2+1,(start + end)/2 + 1 , end,num);
}
}
int main()
{
int i;
//数据先离散化
fun();memset(t,0,sizeof(t));
//构造线段树
int k=0,temp[1010];
for(i=n; i>0; i--)
{
temp[k++]=add(1,llMin,llMax,a[i]);
}
for(i=k-1;i>=0;i--)
cout<<temp[i]<<" ";
return 0;
}