Ultra-QuickSort (求逆序数+离散化处理)、Cows、Stars【树状数组】

时间:2022-03-29 04:58:01

一、Ultra-QuickSort(树状数组求逆序数)

题目链接(点击)

Ultra-QuickSort

Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 73943   Accepted: 27692

Description

Ultra-QuickSort (求逆序数+离散化处理)、Cows、Stars【树状数组】

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence

9 1 0 5 4 ,

Ultra-QuickSort produces the output

0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

思路:

题目表达的很清楚,是想要求输入序列的逆序数(判断序列中的每一位,在之前的数中比该位表示的数大的个数的总和)

例如:

9 1 0 5 4 这个序列

在1前面比1大的有1个 (9) 所以 ans+=1;

在0前面比0大的有两个 (9、1)所以 ans+=2;

同理 ans+=1;ans+=2;

所以ans=6即表示序列的逆序数。

求逆序数的方法如下(暴力):

** 还以上面的序列为例:9 1 0 5 4

给上面每个值按照位置编号从1~5

从第一位开始遍历:先将vis[9]=1;数字9看做位置序号;然后从1开始遍历vis[1]到vis[9]并求和 记录sum=getsum[9];

则 ans+=(i-getsum[9]); 此时i=1,getsum[9]=1(1是因为仅有vis[9]=1); 所以 ans+=(1-1);

往后过程同理;

暴力代码:

肯定会TLE但是可以使用树状数组优化求和过程使O(n²)的复杂度降为O(nlgn);

    for(int i=1;i<=n;i++){
int t=i;vis[a[i]]=1; //整个过程相当于求i-getsum[a[i]];
for(int j=1;j<=a[i];j++){
if(vis[j]==1){
t--;
}
}
ans+=t;
}

**会遇到的问题:

从上面可以知道输入的9看做序号i 但如果9超过数组范围怎么办?

离散化处理:将输入的a[i] 从1开始排列到n 前提是n个数不能重复

例如上面 9 1 0 5 4

离散化结果为:5 2 1 4 3

离散化处理代码:

#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAX=1e5;
struct node{
int count;
int num;
}edge[MAX+5];
bool cmp1(node a, node b)
{
return a.count<b.count;
}
bool cmp2(node a, node b)
{
return a.num<b.num;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&edge[i].count);
edge[i].num=i;
}
sort(edge+1,edge+n+1,cmp1); //按照count大小排序
for(int i=1;i<=n;i++){
edge[i].count=i; //给count重新赋值1~n
}
sort(edge+1,edge+n+1,cmp2); //按照num排序恢复最初大小关系
for(int i=1;i<=n;i++){
printf("%d ",edge[i].count);
}
printf("\n");
return 0;
}

AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX=5e5;
struct node{
LL i;
LL num;
}edge[MAX+5];
LL n;
LL vis[MAX+5];
bool cmp1(node a, node b)
{
return a.num<b.num;
}
bool cmp2(node a, node b)
{
return a.i<b.i;
}
void add(LL x,LL y)
{
for(LL i=x;i<=n;i+=i&(-i)){
vis[i]+=y;
}
}
LL getsum(LL x)
{
LL ans=0;
for(LL i=x;i>=1;i-=i&(-i)){
ans+=vis[i];
}
return ans;
}
int main()
{
while(~scanf("%lld",&n)&&n){
memset(vis,0,sizeof(vis));
for(LL i=1;i<=n;i++){
scanf("%lld",&edge[i].num);
edge[i].i=i;
}
sort(edge+1,edge+n+1,cmp1);
LL top=1;
for(LL i=1;i<=n;i++){
edge[i].num=top++;
}
sort(edge+1,edge+n+1,cmp2);
LL ans=0;
for(LL i=1;i<=n;i++){
LL t=i;
add(edge[i].num,1);
ans+=(t-getsum(edge[i].num));
}
printf("%lld\n",ans);
}
return 0;
}

二、Cows

题目链接(点击)

Cows

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 23665   Accepted: 7962

Description

Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. 

Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E]. 

But some cows are strong and some are weak. Given two cows: cowi and cowj, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cowi is stronger than cowj. 

For each cow, how many cows are stronger than her? Farmer John needs your help!

Input

The input contains multiple test cases. 

For each test case, the first line is an integer N (1 <= N <= 105), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 105) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge. 

The end of the input contains a single 0.

Output

For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cowi.

Sample Input

3
1 2
0 3
3 4
0

Sample Output

1 0 0

Hint

Huge input and output,scanf and printf is recommended.

思路:

开始做这个题想到的也是暴力(看数据知道会TLE),后来换了思路但又感觉x和y没有关系 会不太好控制,就不知怎么办了

看了讲解:

先将y从大到小排列 这样就保证了后面输入的y值一定是比前面的要小 然后从1遍历数组vis求和便可以得到有多少个符合条件的 然后将所有数加起来便可以得到结果。但是也要注意数据范围是(0 <= S < E <= 105) 有0在里面就没办法使用树状数组求和所以add(x)的时候最好是add(x+1),同时sum(x) 变为 sum(x+1),这样就避免了那种情况。

代码也不是特别麻烦 还要注意while输入 每次使用数组前都要memset一下 初始化数组。

AC代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=1e5;
struct node{
int l;
int r;
int num;
}edge[MAX+5];
int vis[MAX+5];
int ans[MAX+5];
bool cmp(node a,node b)
{
if(a.r==b.r){
return a.l<b.l;
}
return a.r>b.r;
}
int sum(int x)
{
int ans=0;
for(int i=x;i>0;i-=i&(-i)){
ans+=vis[i];
}
return ans;
}
void add(int x, int a)
{
for(int i=x;i<=MAX;i+=(i&(-i))){
vis[i]+=a;
}
}
int main()
{
int n;
while(~scanf("%d",&n),n){
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
for(int i=0;i<n;i++){
scanf("%d%d",&edge[i].l,&edge[i].r);
edge[i].num=i;
}
sort(edge,edge+n,cmp);
for(int i=0;i<n;i++){
if(i&&edge[i].l==edge[i-1].l&&edge[i].r==edge[i-1].r){
ans[edge[i].num]=ans[edge[i-1].num];
}
else{
ans[edge[i].num]=sum(edge[i].l+1);
}
add(edge[i].l+1,1);
}
for(int i=0;i<n;i++){
if(i==0){
printf("%d",ans[i]);
}
else{
printf(" %d",ans[i]);
}
}
printf("\n");
}
return 0;
}

三、Stars 

题目链接(点击)

Cows

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 23665   Accepted: 7962

Description

Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. 

Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E]. 

But some cows are strong and some are weak. Given two cows: cowi and cowj, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cowi is stronger than cowj. 

For each cow, how many cows are stronger than her? Farmer John needs your help!

Input

The input contains multiple test cases. 

For each test case, the first line is an integer N (1 <= N <= 105), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 105) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge. 

The end of the input contains a single 0.

Output

For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cowi.

Sample Input

3
1 2
0 3
3 4
0

Sample Output

1 0 0

Hint

Huge input and output,scanf and printf is recommended.

思路:

和上面的stars基本一样而且还不需要排序

排序限定了y从小到大 只需要判断x比其小的数目即可

注意:该题目范围还是从0开始 所以要注意add(x) 变为 add(x+1)

同时sum(x) 变为 sum(x+1)

AC代码:

#include<stdio.h>
typedef long long LL;
const int MAX=42000;
struct node{
LL x;
LL y;
LL num;
}edge[MAX+5];
LL vis[MAX+5];
LL ans[MAX+5],flag[MAX+5];
void add(LL x,LL a)
{
for(LL i=x;i<=MAX;i+=i&(-i)){
vis[i]+=a;
}
}
LL sum(int x)
{
LL ans=0;
for(LL i=x;i>0;i-=i&(-i)){
ans+=vis[i];
}
return ans;
} int main()
{
LL n;
scanf("%lld",&n);
for(LL i=0;i<n;i++){
scanf("%lld%lld",&edge[i].x,&edge[i].y);
edge[i].num=i;
}
for(LL i=0;i<n;i++){
if(i&&edge[i].x==edge[i-1].x&&edge[i].y==edge[i-1].y){
ans[edge[i].num]=ans[edge[i-1].num];
}
else{
ans[edge[i].num]=sum(edge[i].x+1);
}
flag[ans[edge[i].num]]++;
add(edge[i].x+1,1);
}
for(LL i=0;i<n;i++){
printf("%lld\n",flag[i]);
}
return 0;
}