POI 2001 Goldmine (Treap)

題目鏈接

Goldmine

Time Limit:1000MSMemory Limit:30000KB
Total Submit:157Accepted:50

Description

Byteman, one of the most deserving employee of The Goldmine of Byteland, is about to retire by the end of the year. The Goldmine management would like to reward him in acknowledgment of his conscientious work. As a reward Byteman may receive a small lot - a rectangular piece of the mine's area with sides of length s and w parallel to the axes of the coordinate system. He may choose the location of the lot. Of course, a value of the lot depends on the location. The value of the lot is a number of gold nuggets in the area of the lot (if a nugget lies on the border of the lot, then it is in the area of the lot). Your task is to write a program which computes the maximal possible value of the lot (the value of the lot with the best location). In order to simplify we assume that the terrain of the Goldmine is boundless, but the area of gold nuggets occurrence is limited.

Task
Write a program which:

1.reads the location of gold nuggets,
2.computes the maximal value of a lot (i.e. the maximal number of gold nuggets on the lot of given size),
3.writes the result .

Input

In the first line there are two positive integers s and w separated by a single space, (1<=s,w<=10 000); they denote the lengths of lot's sides - parallel to the OX-axe and OY-axe respectively. There is one positive integer n written in the second line, (1<=n<=15 000). It denotes the number of nuggets in the area of the Goldmine. In the following n lines there are written the coordinates of the nuggets. Each of these lines consists of two integers x and y, (-30 000<=x,y<=30 000), separated by a single space and denoting the x and the y coordinate of a nugget respectively.

Output

The out should contain exactly one integer equal to the value of the most valuable lot of a given size.

Sample Input

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

Sample Output

4

Source

POI 2001 III Stage

題意:二維平面上有n個整數點,現在有一個長方形長爲S,寬爲W。長和寬分別與X軸、Y軸平行。問這個矩形最多能覆蓋多少個點?(點在長方形的邊上也算覆蓋)

題解:先將點按X排序,從前到後把點掃一遍,每次把當前點加入集合,維護集合,是集合中點到當前點的距離不超過S。對於當前集合來說,我們要求解一個Y軸方向的長度爲w的區間最多能覆蓋集合中的多少個點?

對於這個問題,設有一個點的縱座標爲y,我們在數組下標y處+1,在數組下標(y+w+1)處-1。那麼數組的前綴和sum[i]就是區間[i-w,i]中點的個數。那麼問題就是求該數組的最大前綴和。

這個問題可以用平衡樹or線段樹or樹狀數組解決。

平衡樹代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<string.h>
#define nn 110000
#define mod 100003
typedef long long LL;
typedef unsigned long long LLU;
using namespace std;
int s,w;
int n;
pair<int,int>gold[nn];
void Sort(pair<int,int>*a,int l,int r)
{
    if(r==l)
        return ;
    int tem=rand()%(r-l+1)+l;
    swap(*(a+tem),*(a+r));
    int i;
    int k=l;
    for(i=l;i<=r;i++)
    {
        if(*(a+i)<=*(a+r))
        {
            swap(*(a+k),*(a+i));
            k++;
        }
    }
    if(k-2>l)
        Sort(a,l,k-2);
    if(k<r)
        Sort(a,k,r);
}
struct node
{
    int val1;
    int key;
    int val2;
    int num;
    int sum;
    int maxsum;
    node* son[2];
}*root;
void update(node *id)
{
    id->sum=id->val2;
    if(id->son[0]!=NULL)
    {
        id->sum+=id->son[0]->sum;
        id->maxsum=max(id->son[0]->maxsum,id->son[0]->sum+id->val2);
    }
    else
        id->maxsum=id->val2;
    if(id->son[1]!=NULL)
    {
        id->sum+=id->son[1]->sum;
        if(id->son[0]!=NULL)
            id->maxsum=max(id->maxsum,id->son[0]->sum+id->val2+id->son[1]->maxsum);
        else
            id->maxsum=max(id->maxsum,id->val2+id->son[1]->maxsum);
    }
}
void Rotate(node* &id,int d)
{
    node* tem=id->son[d];
    id->son[d]=tem->son[d^1];
    tem->son[d^1]=id;
    update(id);
    update(tem);
    id=tem;
}
void Insert(node* &id,pair<int,int>val)
{
    if(id==NULL)
    {
        id=new node;
        id->num=1;
        id->val1=val.first;
        id->val2=val.second;
        id->key=(rand()*rand())%nn;
        id->sum=val.second;
        id->maxsum=val.second;
        id->son[0]=id->son[1]=NULL;
        return ;
    }
    if(id->val1==val.first)
    {
        id->num++;
        id->val2+=val.second;
        update(id);
    }
    else if(id->val1>val.first)
    {
        Insert(id->son[0],val);
        update(id);
        if(id->son[0]->key<id->key)
        {
            Rotate(id,0);
        }
    }
    else
    {
        Insert(id->son[1],val);
        update(id);
        if(id->son[1]->key<id->key)
        {
            Rotate(id,1);
        }
    }
}
void Delete(node *&id,pair<int,int>val)
{
    if(id==NULL)
        return ;
    if(id->val1==val.first)
    {
        if(id->num==1)
        {
            if(id->son[0]==NULL)
                id=id->son[1];
            else if(id->son[1]==NULL)
                id=id->son[0];
            else
            {
                if(id->son[0]->key<id->son[1]->key)
                {
                    Rotate(id,0);
                    Delete(id->son[1],val);
                }
                else
                {
                    Rotate(id,1);
                    Delete(id->son[0],val);
                }
            }
        }
        else
        {
            id->num--;
            id->val2-=val.second;
        }
    }
    else if(id->val1>val.first)
    {
        Delete(id->son[0],val);
    }
    else
    {
        Delete(id->son[1],val);
    }
    if(id!=NULL)
        update(id);
}
int main()
{
    int i;
    while(scanf("%d%d",&s,&w)!=EOF)
    {
        root=NULL;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&gold[i].first,&gold[i].second);
        }
        Sort(gold,1,n);
        int pre=1;
        int ans=0;
        for(i=1;i<=n;i++)
        {
            while(gold[i].first-gold[pre].first>s)
            {
                Delete(root,make_pair(gold[pre].second,1));
                Delete(root,make_pair(gold[pre].second+w+1,-1));
                pre++;
            }
            Insert(root,make_pair(gold[i].second,1));
            Insert(root,make_pair(gold[i].second+w+1,-1));
            ans=max(ans,root->maxsum);
        }
        printf("%d\n",ans);
    }
    return 0;
}

線段樹代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<string.h>
#include<vector>
#define nn 310000
#define mod 100003
typedef long long LL;
typedef unsigned long long LLU;
using namespace std;
int s,w;
int n;
pair<int,int>gold[nn];
void Sort(pair<int,int>* a,int l,int r)
{
    if(l==r)
        return ;
    int tem=(rand()*rand())%(r-l+1)+l;
    swap(*(a+tem),*(a+r));
    int k=l;
    for(int i=l;i<=r;i++)
    {
        if(*(a+i)<=*(a+r))
        {
            swap(*(a+i),*(a+k));
            k++;
        }
    }
    if(k-2>l)
        Sort(a,l,k-2);
    if(k<r)
        Sort(a,k,r);
}
int L[nn],R[nn];
int sum[nn],presum[nn];
void build(int id,int l,int r)
{
    L[id]=l;
    R[id]=r;
    sum[id]=presum[id]=0;
    if(l==r)
    {
        return ;
    }
    int mid=(l+r)/2;
    build(2*id,l,mid);
    build(2*id+1,mid+1,r);
}
void push_up(int id)
{
    sum[id]=sum[2*id]+sum[2*id+1];
    presum[id]=max(presum[2*id],sum[2*id]+presum[2*id+1]);
}
void update(int id,int wei,int val)
{
    if(L[id]==R[id])
    {
        sum[id]+=val;
        presum[id]+=val;
        return ;
    }
    int mid=(L[id]+R[id])/2;
    if(wei<=mid)
    {
        update(2*id,wei,val);
    }
    else
        update(2*id+1,wei,val);
    push_up(id);
}
int ve[nn];
map<int,int>ma;
int main()
{
    int i;
    while(scanf("%d%d",&s,&w)!=EOF)
    {
        scanf("%d",&n);
        int lv=0;
        ma.clear();
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&gold[i].first,&gold[i].second);
            ve[++lv]=gold[i].second;
            ve[++lv]=gold[i].second+w+1;
        }
        sort(ve+1,ve+lv+1);
        lv=unique(ve+1,ve+lv+1)-ve-1;
        for(i=1;i<=lv;i++)
        {
            ma[ve[i]]=i;
        }
        Sort(gold,1,n);
        int pre=1;
        build(1,1,lv);
        int ans=0;
        for(i=1;i<=n;i++)
        {
            while(gold[i].first-gold[pre].first>s)
            {
                update(1,ma[gold[pre].second],-1);
                update(1,ma[gold[pre].second+w+1],1);
                pre++;
            }
            update(1,ma[gold[i].second],1);
            update(1,ma[gold[i].second+w+1],-1);
            ans=max(ans,presum[1]);
        }
        printf("%d\n",ans);
    }
    return 0;
}


發佈了213 篇原創文章 · 獲贊 4 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章