zoukankan      html  css  js  c++  java
  • 线段树或树状数组或归并(逆序对)

    题意:给出一组数(没有相同的数),可以交换相邻的两个数,问最少多少次可以是这组数是单调递增的?

    1、树状数组+离散化

    思路:另开一个离散数组递增排序,下标即为该数为第几小,n-pos+1把大的数放前面,每次询问前面比该数大的数有几个。

    //#include<bits/stdc++.h>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <string.h>
    #include <vector>
    typedef long long ll ;
    #define int ll
    #define mod 1000000007
    #define gcd __gcd
    #define rep(i , j , n) for(int i = j ; i <= n ; i++)
    #define red(i , n , j)  for(int i = n ; i >= j ; i--)
    #define ME(x , y) memset(x , y , sizeof(x))
    //ll lcm(ll a , ll b){return a*b/gcd(a,b);}
    //ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;}
    //int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-=ans/i;while(x%i==0)x/=i;}if(x>1)ans-=ans/x;return ans;}
    //const int N = 1e7+9; int vis[n],prime[n],phi[N];int euler2(int n){ME(vis,true);int len=1;rep(i,2,n){if(vis[i]){prime[len++]=i,phi[i]=i-1;}for(int j=1;j<len&&prime[j]*i<=n;j++){vis[i*prime[j]]=0;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}else{phi[i*prime[j]]=phi[i]*phi[prime[j]];}}}return len}
    #define INF  0x3f3f3f3f
    #define PI acos(-1)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define lson l,mid,root<<1
    #define rson mid+1,r,root<<1|1
    #define cin() scanf("%lld" , &x);
    using namespace std;
    const int esp = 1e-6;
    const int maxn = 5e5+5;
    int b[maxn] , a[maxn];
    int  n;
    int c[maxn];
    int lowerbit(int x){
        return x&(-x);
    }
    
    void add(int x , int val){
        while(x <= n){
            c[x] += val;
            x += lowerbit(x);
        }
    }
    int query(int x){
        int ans = 0 ;
        while(x){
            ans += c[x];
            x -= lowerbit(x);
        }
        return ans;
    }
    void init(){
        ME(c , 0);
        ME(b , 0);
    }
    void solve(){
        init();
        rep(i , 1 , n){
            cin >> a[i];
            b[i] = a[i];
        }
        int ans = 0 ;
        sort(b + 1, b + 1 + n);//递增排序
        rep(i , 1 , n){
            int pos = lower_bound(b + 1 , b + 1 + n , a[i]) - b ;//下标即为第几小数
            pos = n - pos + 1 ;//把大的数放去面
            ans += query(pos);//询问该数前面比该数大的数有几个
            add(pos , 1);//把该数插入。
        }
        cout << ans << endl;
    }
    
    signed main()
    {
        //ios::sync_with_stdio(false);
        //cin.tie(0); cout.tie(0);
        //int t ;
        //cin >> t ;
        //while(t--){
        while(~scanf("%lld" , &n) && n)
            solve();
        //}
    }
    
    线段树思路:建树都标记为1 ,将数与对应编号联系起来, 根据数大小排序 ,依次询问 1 - (编号-1) 区间和 , 再更新该点为0(避免影响后面查询)。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #define max 32001
    using namespace std;
    const int N = 500009 ;
    long long  ans = 0 ;
    struct Node{
        int l , r , val ;
    }tree[4*N];
    
    struct node{
        int num , index ;
    }m[N];
    
    void build(int l , int r , int root)
    {
        tree[root].l = l , tree[root].r = r ;
        tree[root].val = 1 ;
        if(l == r)
            return ;
        int mid = (tree[root].r + tree[root].l) >> 1 ;
        build(l , mid , root*2);
        build(mid+1 , r , root * 2+1);
        tree[root].val = tree[root*2].val + tree[root*2+1].val ;
    }
    
    
    bool cmp(struct node a , struct node b)
    {
        return a.num < b.num ;
    }
    
    void query(int l , int r , int root)
    {
        if(tree[root].l >= l && tree[root].r <= r)
        {
            ans += tree[root].val ;
            return ;
        }
        int mid =( tree[root].r + tree[root].l ) >> 1;
        if(l <= mid)
            query(l , r, root*2);
        if(r > mid)
            query(l , r, root *2+1);
    }
    
    void update(int x , int root)
    {
        if(tree[root].l == tree[root].r)
        {
            tree[root].val = 0 ;
            return ;
        }
        int mid = (tree[root].l + tree[root].r) >> 1 ;
        if(x <= mid)
            update(x , root*2);
        else
            update(x , root*2+1);
        tree[root].val = tree[root*2].val + tree[root*2+1].val ;
    }
    
    int main()
    {
        int n ;
        while(~scanf("%d" , &n) && n)
        {
            build(1 , n , 1) ;
            for(int i = 1 ; i <= n ; i ++)
            {
                scanf("%d" ,&m[i].num);
                m[i].index = i ;
            }
            sort(m+1 , m + n+1 , cmp);
            for(int i = 1 ; i <= n ; i++)
            {
                int r ;
                r = m[i].index ;
                query(1 , r-1 , 1);
                update(r , 1);
            }
            cout << ans << endl ;
            ans = 0 ;
        }
    
    
        return 0 ;
    }

    树状数组:思路与线段树一样

    编号并赋值为1;

    例如 :数值: 9 1 0 5 4   排序后 0 1 4 5 9

    编号:     1 2 3 4 5         3 2 5 4 1    现在只需要求编号的 getsum(r - 1) 的和 ,并更新 update(r , -1 ).

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #define max 32001
    using namespace std;
    const int N = 500009 ;
    int c[N] ;
    int n ;
    
    struct Node{
        int val , index ;
    }a[N];
    
    int lowerbit(int x)
    {
        return x & (-x);
    }
    
    void update(int x , int val)
    {
        for(int i = x ; i <= n ; i += lowerbit(i))
        {
            c[i] += val ;
        }
    }
    
    int getsum(int x)
    {
        int ans = 0 ;
        for(int i = x  ; i > 0 ; i -= lowerbit(i))
        {
            ans += c[i];
        }
        return ans ;
    }
    
    bool cmp(struct Node a , struct Node b)
    {
        return a.val < b.val ;
    }
    
    int main()
    {
        while(~scanf("%d" , &n) && n)
        {
            for(int i = 1 ; i <= n ; i++)
            {
                scanf("%d" , &a[i].val);
                a[i].index = i ;
                update(i , 1);
            }
            long long  ans = 0 ;
            sort(a + 1, a + n + 1 , cmp);
            for(int i = 1 ; i <= n ; i++)
            {
                int r ;
                r = a[i].index ;
                ans += getsum(r - 1);
                update(r , -1);
            }
            cout << ans <<endl ;
        }
    
    
        return 0 ;
    }

  • 相关阅读:
    C++笔记(2018/2/6)
    2017级面向对象程序设计寒假作业1
    谁是你的潜在朋友
    A1095 Cars on Campus (30)(30 分)
    A1083 List Grades (25)(25 分)
    A1075 PAT Judge (25)(25 分)
    A1012 The Best Rank (25)(25 分)
    1009 说反话 (20)(20 分)
    A1055 The World's Richest(25 分)
    A1025 PAT Ranking (25)(25 分)
  • 原文地址:https://www.cnblogs.com/nonames/p/11268681.html
Copyright © 2011-2022 走看看