线段树求逆序数+北化校赛D题

Ultra-QuickSort

 OpenJ_Bailian - 2299 

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.InputThe 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.OutputFor 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
思路:对于每次输入的数据,即刻判断其前面比它大的数的个数,范围是当前这个数+1,到最大值,然后立刻更新。因为数据很大,需要离散化,具体看代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6;
struct node{
    int l;
    int r;
    int sum;
}e[maxn<<2];
struct tree{
    int pos;
}tree[maxn<<2];
long long sum;
int mp[maxn];
int a[maxn],n;
void build(int l,int r,int cur)
{
    e[cur].l=l;
    e[cur].r=r;
    e[cur].sum=0;
    if(l==r)
        return;
    int mid=(l+r)/2;
    build(l,mid,cur<<1);
    build(mid+1,r,cur<<1|1);
}
void pushup(int cur)
{
    e[cur].sum=e[cur<<1].sum+e[cur<<1|1].sum;
} 
int query(int pl,int pr,int cur)
{
    if(pl<=e[cur].l&&e[cur].r<=pr)
    {
        return e[cur].sum;
    }
    int mid=(e[cur].l+e[cur].r)/2;
    int res=0;
    if(pl<=mid)
         res+=query(pl,pr,cur<<1);
    if(pr>mid)
        res+=query(pl,pr,cur<<1|1);
    return res;
}
void update(int tar,int cur)
{
    if(e[cur].l==e[cur].r)
    {
        e[cur].sum++;
        return;
    }
    int mid=(e[cur].l+e[cur].r)/2;
    if(tar<=mid)
        update(tar,cur<<1);
    else
        update(tar,cur<<1|1);
    pushup(cur);
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        memset(mp,0,sizeof(mp));
        memset(a,0,sizeof(a)); 
        sum=0;
        build(1,maxn,1);
        int t=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            mp[++t]=a[i];
        } 
        sort(mp+1,mp+t+1);
        int cnt=1;
        int R;
        
        for(int i=2;i<=t;i++)
        {
            if(mp[i]!=mp[i-1])
            {
                mp[++cnt]=mp[i];
            }
        }
        for(int i=1;i<=n;i++)
        {
            int ul=lower_bound(mp+1,mp+1+cnt,a[i])-mp;
            tree[i].pos=ul;
        //    cout<<ul<<endl;
        } 
        for(int i=1;i<=n;i++)
        {
            sum+=query(tree[i].pos+1,maxn,1);    
            update(tree[i].pos,1);
        }
        printf("%lld\n",sum);
    }
    
} 

 

Minimum Inversion Number

 HDU - 1394 

 

The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. 

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following: 

a1, a2, ..., an-1, an (where m = 0 - the initial seqence) 
a2, a3, ..., an, a1 (where m = 1) 
a3, a4, ..., an, a1, a2 (where m = 2) 
... 
an, a1, a2, ..., an-1 (where m = n-1) 

You are asked to write a program to find the minimum inversion number out of the above sequences. 

InputThe input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1. 
OutputFor each case, output the minimum inversion number on a single line. 
Sample Input

10
1 3 6 9 0 8 5 7 4 2

Sample Output

16
题意:将一组数循环后移,问逆序数的最少为多少
题解:1、对于某一序列,其中的某一个数a[i]能构成多少个逆序,只须判断在a[i]+1~n的范围内找之前的数是否出现过的次数; 2、然后求出第一个序列的逆序数。 3、由第一个序列的逆序数可以推出它下一个序列的逆序数。 有规律 下一个序列的逆序数 sum = 上一个的sum - a[i] - 1- a[i];如果得出呢 比如说: 序列 3 6 9 0 8 5 7 4 2 1 把3移到后面,则它的逆序数会减少3个(0 2 1) 但同时会增加 n - a[i] - 1个。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define inf 99999999999
 6 using namespace std;
 7 const int maxn=5010;
 8 typedef long long ll;
 9 int n;
10 struct node{
11     int l;
12     int r;
13     int sum;
14 }e[maxn<<2];
15 int a[maxn<<2];
16 void build(int l,int r,int cur)
17 {
18     e[cur].l=l;
19     e[cur].r=r;
20     e[cur].sum=0;
21     if(l==r)
22         return;
23     int mid=(l+r)/2;
24     build(l,mid,cur<<1);
25     build(mid+1,r,cur<<1|1);
26 }
27 ll query(int pl,int pr,int cur)
28 {
29     if(pl<=e[cur].l&&e[cur].r<=pr)
30     {
31         return e[cur].sum;
32     }
33     ll res=0;
34     int mid=(e[cur].l+e[cur].r)/2;
35     if(pl<=mid)
36         res+=query(pl,pr,cur<<1);
37     if(pr>mid)
38         res+=query(pl,pr,cur<<1|1);
39 return res;    
40 }
41 void update(int tar,int cur)
42 {
43     if(e[cur].l==e[cur].r)
44     {
45         e[cur].sum++;
46         return ;
47     }
48     int mid=(e[cur].l+e[cur].r)/2;
49     if(tar<=mid)
50         update(tar,cur<<1);
51     else
52         update(tar,cur<<1|1);
53     e[cur].sum=e[cur<<1].sum+e[cur<<1|1].sum;
54 }
55 int main()
56 {
57     while(~scanf("%d",&n))
58     {
59         int t=n;
60         ll res=0;build(0,n,1);
61         memset(a,0,sizeof(a));
62         for(int i=0;i<n;i++)
63         {
64             scanf("%d",&a[i]);
65             res+=query(a[i]+1,n,1);
66             update(a[i],1);
67         }
68         int k=0;
69         ll ans=inf;
70         ans=res;  
71         for(int i=0;i<n;++i) {  
72             res=res-a[i]+(n-1-a[i]);  
73             ans=min(ans,res);  
74         }  
75         printf("%lld\n",ans);
76     } 
77     
78 }

 

 

问题 D: 积木

时间限制: 1 Sec  内存限制: 128 MB

题目描述

我懒得编故事了  m哥牛逼! 
有n个积木,第i个积木的高度为a[i],求每个积木前面有几个比它矮的积木 

输入


多组输入,每组由两行组成,第一行输入n,第二行输入n个数,为n个积木的高度a[i] 
//(1<=n<=100000)(1<=a[i]<=1000000000) 

输出

每组数据输出n个数,第i个数为第i个积木前面比他矮的积木的个数

样例输入

5
1 2 3 4 5

样例输出

0 1 2 3 4

 注意:多组输入~~~~~~~

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=1e5+10;
  8 struct node{
  9     ll l;
 10     ll r;
 11     long long sum;
 12 }e[maxn<<2];
 13 long long ans[maxn<<2];
 14 struct tree{
 15     ll pos;
 16 }tree[maxn<<2];
 17 long long sum;
 18 long long  mp[maxn];
 19 long long  a[maxn],n;
 20 void build(ll l,ll r,ll cur)
 21 {
 22     e[cur].l=l;
 23     e[cur].r=r;
 24     e[cur].sum=0;
 25     if(l==r)
 26         return;
 27     ll mid=(l+r)/2;
 28     build(l,mid,cur<<1);
 29     build(mid+1,r,cur<<1|1);
 30 }
 31 void pushup(ll cur)
 32 {
 33     e[cur].sum=e[cur<<1].sum+e[cur<<1|1].sum;
 34 }
 35 ll query(ll pl,ll pr,ll cur)
 36 {
 37     if(pl<=e[cur].l&&e[cur].r<=pr)
 38     {
 39         return e[cur].sum;
 40     }
 41     ll mid=(e[cur].l+e[cur].r)/2;
 42     ll res=0;
 43     if(pl<=mid)
 44          res+=query(pl,pr,cur<<1);
 45     if(pr>mid)
 46         res+=query(pl,pr,cur<<1|1);
 47     return res;
 48 }
 49 void update(long long  tar,ll cur)
 50 {
 51     if(e[cur].l==e[cur].r)
 52     {
 53         e[cur].sum++;
 54         return;
 55     }
 56     ll mid=(e[cur].l+e[cur].r)/2;
 57     if(tar<=mid)
 58         update(tar,cur<<1);
 59     else
 60         update(tar,cur<<1|1);
 61     pushup(cur);
 62 }
 63 int main()
 64 {
 65     while(~scanf("%lld",&n))
 66     {
 67          sum=0;
 68         build(1,maxn,1);
 69         ll t=0;
 70         for(ll i=1;i<=n;i++)
 71         {
 72             scanf("%lld",&a[i]);
 73             mp[++t]=a[i];
 74         }
 75         sort(mp+1,mp+t+1);
 76         ll cnt=1;
 77         ll R;
 78 
 79         for(ll i=2;i<=t;i++)
 80         {
 81             if(mp[i]!=mp[i-1])
 82             {
 83                 mp[++cnt]=mp[i];
 84             }
 85         }
 86         for(ll i=1;i<=n;i++)
 87         {
 88             ll ul=lower_bound(mp+1,mp+1+cnt,a[i])-mp;
 89             tree[i].pos=ul;
 90         //    cout<<ul<<endl;
 91         }
 92         for(ll i=1;i<=n;i++)
 93         {
 94             sum+=query(1,tree[i].pos-1,1);
 95             ans[i]=sum;
 96             //printf("%lld ",sum);
 97             update(tree[i].pos,1);
 98         }
 99         for(ll i=1;i<n;i++)
100         {
101             printf("%lld ",ans[i]-ans[i-1]);
102         }
103         printf("%lld\n",ans[n]-ans[n-1]);
104 
105        // printf("%lld\n",sum);
106     }
107 
108 }

 


posted @ 2018-09-26 20:42  *starry*  阅读(179)  评论(0编辑  收藏  举报