zoukankan      html  css  js  c++  java
  • POI2001 Gold mine(二叉排序树 黑书经典)

    采矿(KOP)

        金矿的老师傅年底要退休了。经理为了奖赏他的尽职尽责的工作,决定送他一块长方形地。长度为S,宽度为W。老师傅可以自己选择这块地。显然其中包含的采金点越多越好。你的任务就是计算最多能得到多少个采金点。如果一个采金点的位置在长方形的边上,它也应当被计算在内。
    任务:
        读入采金点的位置。计算最大的价值。
    输入:
        文件KOP.IN的第一行是S和W,(1<=s,w<=10 000);他们分别平行于OX坐标和OY坐标,指明了地域的尺寸。接下来一行是整数n (1<=n<=15 000),表示采金点的总数。然后是n行,每行两个整数,给出了一个采金点的坐标。坐标范围是(-30 000<=x,y<=30 000)。
    输出:
        一个整数,最多的采金点数。
    样例输入
    1 2
    12
    0 0
    1 1
    2 2
    3 3
    4 5
    5 5
    4 2
    1 4
    0 5
    5 0
    2 3
    3 2
    样例输出
    4

    果然POI的题目真是经典,在看题解时学到了很多的东西  也是从黑书中寻觅到的

    运用到的知识很多,却很清晰

    其中一些技巧看似很简单却十分巧妙

    这时我才感觉到二叉排序树强大之处
    而更详细的题解方法  参见<二分法与统计问题>李睿神牛
    #include<cstdio>
    #define maxn 15005
    #define max(a,b) ((a)>(b)?(a):(b))
    int n,m,s,w,num,ans,x[2*maxn],y[2*maxn],yy[2*maxn];
    struct {
        int y,sum,maxsum;
    }t[4*maxn];
    
    void qsX(int,int);
    void qsY(int,int);
    void buildtree(int);
    void ins(int,int,int);
    
    int main(){
        FILE *in=fopen("kop.in","r");
        FILE *out=fopen("kop.out","w");
        int i,j,k;
        for(i=0;i<=4*maxn-1;i++) t[i].y=-30001;
        fscanf(in,"%d%d%d",&s,&w,&n);
        for(i=1;i<=n;i++){
            fscanf(in,"%d%d",&x[i],&y[i]);
            yy[i]=y[i];
            yy[n+i]=y[i]+w+1;
        }
        yy[2*n+1]=-30001;
        qsY(1,2*n);
        m=0;
        for(i=1;i<=2*n;i++)
            if(yy[i]!=yy[i+1]) yy[++m]=yy[i];
        num=0;
        buildtree(1);
        qsX(1,n);
        i=1;j=1;k=x[j];
        while(i<=n&&j<=n){
            while(x[i]<=k+s&&i<=n){
                ins(1,y[i],1);
                ins(1,y[i]+w+1,-1);
                i++;
            }
            if(ans<t[1].maxsum) ans=t[1].maxsum;
            while(x[j]==k&&j<=n){
                ins(1,y[j],-1);
                ins(1,y[j]+w+1,1);
                j++;
            }
            k=x[j];
        }
        fprintf(out,"%d",ans);
        fclose(in);fclose(out);
        return 0;
    }
    
    
    void qsX(int l,int r){
        int i=l,j=r,k=x[(l+r)/2],t;
        do{
            while(x[i]<k) ++i;
            while(x[j]>k) --j;
            if(i<=j){
                t=x[i];x[i]=x[j];x[j]=t;
                t=y[i];y[i]=y[j];y[j]=t;
                ++i;--j;
            }
        }while(i<j);
        if(i<r) qsX(i,r);
        if(j>l) qsX(l,j);
    }
    void qsY(int l,int r){
        int i=l,j=r,k=yy[(l+r)/2],t;
        do{
            while(yy[i]<k) ++i;
            while(yy[j]>k) --j;
            if(i<=j){
                t=yy[i];yy[i]=yy[j];yy[j]=t;
                ++i;--j;
            }
        }while(i<j);
        if(i<r) qsY(i,r);
        if(j>l) qsY(l,j);
    }
    void buildtree(int now){
        if(2*now<=m) buildtree(2*now);
        t[now].y=yy[++num];
        t[now].sum=t[now].maxsum=0;
        if(2*now+1<=m) buildtree(2*now+1);
    }
    void ins(int now,int num,int p){
        if(num<t[now].y) ins(now*2,num,p);
        if(num>t[now].y) ins(now*2+1,num,p);
        t[now].sum+=p;
        t[now].maxsum=max(t[now*2].maxsum,max(t[now].sum-t[now*2+1].sum,t[now].sum-t[now*2+1].sum+t[now*2+1].maxsum));
    }


  • 相关阅读:
    JS绑定种类汇总
    JS的块级作用域
    JS中的几种函数
    区分词法作用域(js)与动态作用域(精!)
    JS Dom节点操作demo!
    JS作用域相关知识(#精)
    js解析器(重要!)
    JS之鼠标在盒子中的位置
    JS之鼠标跟随
    JS之事件对象体验
  • 原文地址:https://www.cnblogs.com/Mathics/p/3681177.html
Copyright © 2011-2022 走看看