• 【树状数组】【P3608】平衡的照片


    传送门

    Description

    FJ正在安排他的N头奶牛站成一排来拍照。(1<=N<=100,000)序列中的第i头奶牛的高度是h[i],且序列中所有的奶牛的身高都不同。

    就像他的所有牛的照片一样,FJ希望这张照片看上去尽可能好。他认为,如果L[i]和R[i]的数目相差2倍以上的话,第i头奶牛就是不平衡的。(L[i]和R[i]分别代表第i头奶牛左右两边比她高的数量)。如果L[i]和R[i]中较大者比较小者的数量严格多两倍的话,这头奶牛也是不平衡的。FJ不希望他有太多的奶牛不平衡。

    请帮助FJ计算不平衡的奶牛数量。

    Input

    第一行一个整数N。接下N行包括H[1]到H[n],每行一个非负整数(不大于1,000,000,000)。

    Output

    请输出不平衡的奶牛数量。

    Sample Input

    7
    34
    6
    23
    0
    5
    99
    2

    Sample Output

    3

    Solution

    考虑n2暴力做法显然是枚举每头牛,然后向左右枚举进行计数。

    但是显然TLE。考虑优化。由于题目中要求求出比第i头牛大的牛,而事实上比第i头牛矮的牛是否处理是不影响i的答案的,于是我们发现了无后效性。

    考虑排序后以身高降序作为阶段,这样每次处理时求出坐标在i左边和在i右边的比i高的牛的个数。由于以这些牛已经被计算过了,所以事实上我们需要求的就是i两侧已经被处理过的牛的个数。在每次查询完毕后,我们将当前牛标记为被处理过。记处理过为1,为处理过为0。那么显然这是一个单点修改,区间查询的数据结构问题。树状数组可破。

    Code

    #include<cstdio>
    #include<algorithm>
    #define maxn 100010
    #define ci const int
    
    inline void qr(int &x) {
        char ch=getchar(),lst=NULL;
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if(lst=='-') x=-x;
    }
    
    template <typename T>
    inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T &a) {if(a>=0) return a;return -a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    struct M {
        int num,v;
    };
    M MU[maxn];
    inline bool cmp (const M &a,const M &b) {return a.v>b.v;}
    
    int n,cnt;
    int tree[maxn];
    inline int lowbit(ci x) {return x&(-x);}
    
    int ask(register int);
    void add(register int);
    
    int main() {
        qr(n);
        for(register int i=1;i<=n;++i) {qr(MU[i].v);MU[i].num=i;}
        std::sort(MU+1,MU+1+n,cmp);
        for(register int i=1;i<=n;++i) {
            int a=ask(MU[i].num),b=i-a-1;
            if(a<b) mswap(a,b);
            if(b*2<a) ++cnt;
            add(MU[i].num);
        }
        printf("%d
    ",cnt);
        return 0;
    }
    
    int ask(register int x) {
        register int ans=0;
        while(x>0) {
            ans+=tree[x];x-=lowbit(x);
        }
        return ans;
    }
    
    void add(register int x) {
        while(x<=n) {
            ++tree[x];
            x+=lowbit(x);
        }
    }

    Summary

    register大法好,从此加入register邪教

  • 相关阅读:
    mysql的备份与恢复(windows、Linux并拷贝至备机)
    eclipse导出可执行jar
    ORCLE中两张表对比更新合入(MERGE INTO)
    js中事件冒泡的问题
    Spring事务传播行为详解
    Java中的锁分类与使用
    用某浏览器全屏延时启动应用
    Springboot整合WebSocket的交互实例(点对点、点对面)
    Windows程序设计------字体不等宽引出的问题及其细节知识
    关于VS2013使用constexpr报错问题
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9410471.html
Copyright © 2020-2023  润新知