zoukankan      html  css  js  c++  java
  • POJ 2464 Brownie Points II --树状数组

    题意: 有点迷。有一些点,Stan先选择某个点,经过这个点画一条竖线,Ollie选择一个经过这条直接的点画一条横线。Stan选这两条直线分成的左下和右上部分的点,Ollie选左上和右下部分的点。Stan画一条竖线之后,Ollie有很多种选择,在所有选择中,Stan能获得 “分数最小值的最大值” ,而Ollie的选择便是让自己越多越好。问最后Stan最多能得到的分数是多少,以及在这种情况下Ollie能得到的分数有多少种可能。

    解法: 因为Stan先选,然后主动权在Ollie手中,Ollie会优先让自己得到更多的分数,然后再考虑让Stan得到的分数最小。然后才能求得Stan得到的“分数最小值的最大值”。

    既然是Stan先选,那么我们最好按x从小到大排序,y坐标离散,依次处理,又因为在同一条竖线可能有很多店,所以直到坐标变化时才来同一处理那些横坐标相同的点,Ollie在这些点对应的纵坐标中做选择,使达到上述说的效果。

    由于竖线往右移,那么维护两个树状数组,一个是当前竖线右边的点的情况,一个是左边的。然后扫过去,遇到p[i].x!=p[i-1].x时,就可以处理前面的一个或多个横坐标相同的点了,然后按上述说的做就行了。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <set>
    using namespace std;
    #define N 200007
    
    struct node{
        int x,y;
    }p[N];
    int n,maxi;
    int L[N],R[N],a[N],b[N];
    int lowbit(int x) { return x&-x; }
    int cmp1(node ka,node kb) { return ka.x < kb.x; }
    int cmp2(node ka,node kb) { return ka.y < kb.y; }
    
    void modify(int *c,int x,int val)
    {
        while(x <= maxi)
            c[x] += val, x += lowbit(x);
    }
    
    int getsum(int *c,int x)
    {
        int res = 0;
        while(x > 0) { res += c[x]; x -= lowbit(x); }
        return res;
    }
    
    int main()
    {
        int i,j;
        while(scanf("%d",&n)!=EOF && n)
        {
            maxi = 0;
            for(i=1;i<=n;i++)
                scanf("%d%d",&p[i].x,&p[i].y);
            sort(p+1,p+n+1,cmp1);                         //....离散
            for(i=1;i<=n;i++)                           
            {
                if(p[i].x == p[i-1].x) a[i] = a[i-1];
                else a[i] = a[i-1]+1;
            }
            for(i=1;i<=n;i++) p[i].x = a[i];
            sort(p+1,p+n+1,cmp2);
            for(i=1;i<=n;i++)    
            {
                if(p[i].y == p[i-1].y) b[i] = b[i-1];
                else b[i] = b[i-1]+1;
                maxi = max(maxi,b[i]);
            }
            for(i=1;i<=n;i++) p[i].y = b[i];               //离散....
            memset(L,0,sizeof(L));
            memset(R,0,sizeof(R));
            for(i=1;i<=n;i++)
                modify(R,p[i].y,1);
            int Stan = -1,ollie,stan,start = 1;
            sort(p+1,p+n+1,cmp1);
            p[n+1].x = -1,p[n+1].y = -1;
            set<int> Ollie;
            for(i=2;i<=n+1;i++)
            {
                if(p[i].x == p[i-1].x) continue;
                stan = ollie = -1;
                for(j=start;j<i;j++)
                    modify(R,p[j].y,-1);
                for(j=start;j<i;j++)
                {
                    int pos = p[j].y;
                    int STAN = getsum(R,maxi)-getsum(R,pos)+getsum(L,pos-1);   //右上+左下
                    int OLLIE = getsum(L,maxi)-getsum(L,pos)+getsum(R,pos-1);  //左上+右下
                    if(OLLIE == ollie) stan = min(stan,STAN);     //在保证Ollie取最多的情况下让Stan得分最少
                    else if(OLLIE > ollie) stan = STAN, ollie = OLLIE;
                }
                if(stan > Stan) Stan = stan, Ollie.clear(), Ollie.insert(ollie);
                else if(stan == Stan) Ollie.insert(ollie);
                for(j=start;j<i;j++)
                    modify(L,p[j].y,1);
                start = i;
            }
            printf("Stan: %d; Ollie:",Stan);
            for(set<int>::iterator it=Ollie.begin();it!=Ollie.end();it++)
                printf(" %d",*it);
            printf(";
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    吴裕雄--天生自然C++语言学习笔记:C++ 引用
    吴裕雄--天生自然C++语言学习笔记:C++ 指针
    吴裕雄--天生自然C++语言学习笔记:C++ 字符串
    吴裕雄--天生自然C++语言学习笔记:C++ 数组
    吴裕雄--天生自然C++语言学习笔记:C++ 数字
    吴裕雄--天生自然C++语言学习笔记:C++ 函数
    吴裕雄--天生自然C++语言学习笔记:C++ 判断
    HiHoCoder1671 : 反转子串([Offer收割]编程练习赛41)(占位)
    HihoCoder1670 : 比赛日程安排([Offer收割]编程练习赛41)(模拟)
    POJ3417Network(LCA+树上查分||树剖+线段树)
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4060660.html
Copyright © 2011-2022 走看看