zoukankan      html  css  js  c++  java
  • hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792

    题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值。

    解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和b整个序列有多少个逆序对,对吧。然后对于每一个b有x个a满足条件,所以对于当前b,能够满足条件的就是(x*所有的逆序对的个数 - 逆序对中包涵a和b的个数)。所有逆序对很容易就可以用树状数组求出来,x也就是b前面有多少个小于编号b代表的值得个数,也很容易求出来,然后包涵a和b个数的逆序对呢,a前面大于A[a]的个数和a后面小于A[a]的个数,b也是一样的。

    设x为对于每个b满足条件的a的个数,na代表和a有关系的逆序对,nb代表和b有关系的逆序对,tot代表所有的逆序对个数,然后对于每一个b就有 tot*x - nb*x - (所有na的值)。

    代码:

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<cstring>
    #include<queue>
    #include<set>
    #include<string>
    #include<map>
    #define inf 9223372036854775807
    #define INF 9e7+5
    #define PI acos(-1)
    using namespace std;
    typedef long long ll;
    typedef double db;
    const int maxn = 5e4 + 5;
    const int mod = 1e9 + 7;
    const db eps = 1e-9;
    ll n, c[maxn], a[maxn], num[maxn], tot, cc[maxn], lar[maxn], b[maxn];
    
    struct pos {
        ll a, ord, la;
    } q[maxn];
    
    void init() {
        tot = 0;
        memset(c, 0, sizeof(c));
        memset(cc, 0, sizeof(cc));
        memset(lar, 0, sizeof(lar)); //这个数组好像不用初始化
    }
    
    ll lowbit(ll x) {
        return x & (-x); //求最低位
    }
    
    void updata(ll x, ll p, ll u[]) { //更新
        while (x <= maxn) {
            u[x] += p;
            x += lowbit(x);
        }
    }
    
    ll getsum(ll x, ll u[]) {
        ll ans = 0;
        while (x > 0) {
            ans += u[x];
            x -= lowbit(x);
        }
        return ans;
    }
    bool cmp1(const pos&a, const pos&b)
    {
        return a.a<b.a;
    }
    bool cmp2(const pos&a, const pos&b){
        return a.ord<b.ord;
    }
    
    void solve() {
        while (cin >> n) {
            init();
            for (int i = 1; i <= n; i++) {
                scanf("%I64d", &q[i].a);
                q[i].ord = i;
            }
            int pp = 0; sort(q+1, q+1+n, cmp1);
            q[0].a = -1;
            for (int i = 1; i <= n; i++) { //离散化
                if (q[i].a != q[i-1].a) q[i].la = ++pp;
                else {
                    q[i].la = pp;
                }
            }
            sort(q+1, q+1+n, cmp2);
            for (int i = 1; i <= n; i++) {
                lar[i] = i - getsum(q[i].la, c) - 1; //求出每个数前面
                updata(q[i].la, 1, c);              //有多少比他大的数
            }
            memset(c, 0, sizeof(c));
            for (int i = n; i >= 1; i--) {
                num[i] = getsum(q[i].la-1, c);          //求出每个数的
                updata(q[i].la, 1, c); tot += num[i]; //后面比他小的个数
            }
            ll ans = 0; memset(c, 0, sizeof(c));
            for (int i = 1; i <= n; i++) {
                ll tmp = getsum(q[i].la-1, c);   //对当前b满足条件的a的个数
                updata(q[i].la, 1, c);  
                ll tt = getsum(q[i].la-1, cc);  //求出和a有关系的逆序对
                updata(q[i].la, num[i] + lar[i], cc);//num[i]+lar[i]就是和a有关系的逆序对
                ans += tmp * tot - tt - (num[i]+lar[i])*tmp;//这里的num[i]+lar[i]是和b有关系的逆序对
            }
            cout << ans << endl;
        }
    }
    
    int main(){
        //cin.sync_with_stdio(false);
        //freopen("tt.txt", "r", stdin);
        //freopen("isharp.out", "w", stdout);
        solve();
    
        return 0;
    }
    

      

  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/ost-xg/p/5730590.html
Copyright © 2011-2022 走看看