离散化+区间更新+最大结点统计(或优先队列)——[usaco2010 Oct]Soda Machine

有N个人要去膜拜JZ,他们不知道JZ会出现在哪里,因此每个人有一个活动范围,只要JZ出现在这个范围内就能被膜拜, 
伟大的JZ当然希望膜拜他的人越多越好,但是JZ不能分身,因此只能选择一个位置出现,他最多可以被多少人膜拜呢, 
这个简单的问题JZ当然交给你了  

A_i..B_i (1 <=A_i <= B_i <= 1,000,000,000)

N (1 <= N <= 50,000)

4
4 8
1 2
5 10
3 5

输出

3

思路:考虑到a,b的范围很大,N范围小,果断离散化一下,

离散化以后,如果直接 add[] 暴力统计区间,会超时,考虑线段树,使用懒惰标记 500ms

View Code
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;

struct data
{
int c;
int temp;
int no;
}s[100009];

int cmp(data a,data b)
{
return a.c<b.c;
}

int cmp1(data a,data b)
{
return a.no<b.no;
}

int count1[100009];

struct abc
{
int l,r;
int all;
int hou;
}node[400009];

void build(int ll,int rr,int n)
{
node[n].l=ll;
node[n].r=rr;
node[n].hou=0;
if(ll==rr)
{
node[n].all=0;
}

if (ll==rr) return ;
int mid=(ll+rr)>>1;
build(ll,mid,n+n);
build(mid+1,rr,n+n+1);

node[n].all=node[n+n].all+node[n+n+1].all;

}
void updata(int ll,int rr,int a,int n)
{

if (ll<=node[n].l&&node[n].r<=rr&&node[n].hou!=-1)
{
node[n].hou+=a;
node[n].all+=(node[n].r-node[n].l+1)*a;
return ;
}

if(node[n].hou)
{
node[n+n].hou+=node[n].hou;
node[n+n].all+=(node[n+n].r-node[n+n].l+1)*node[n].hou;
node[n+n+1].hou+=node[n].hou;
node[n+n+1].all+=(node[n+n+1].r-node[n+n+1].l+1)*node[n].hou;
node[n].hou=0;
}

int mid=(node[n].l+node[n].r)>>1;
if (rr<=mid) updata(ll,rr,a,n+n);
else if (ll>=mid+1) updata(ll,rr,a,n+n+1);
else
{
updata(ll,mid,a,n+n);
updata(mid+1,rr,a,n+n+1);
}
node[n].all=node[n+n].all+node[n+n+1].all;
}

int search(int ll,int rr,int n)
{
if(node[n].l==ll&&node[n].r==rr)
{
return node[n].all;
}

if(node[n].hou)
{
node[n+n].hou+=node[n].hou;
node[n+n].all+=(node[n+n].r-node[n+n].l+1)*node[n].hou;
node[n+n+1].hou+=node[n].hou;
node[n+n+1].all+=(node[n+n+1].r-node[n+n+1].l+1)*node[n].hou;
node[n].hou=0;
}

int mid=(node[n].l+node[n].r)>>1;
if (rr<=mid) return search(ll,rr,n+n);
else if (ll>mid) return search(ll,rr,n+n+1);
else
{
return search(ll,mid,n+n)+search(mid+1,rr,n+n+1);
}
}

int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i,add=0,ll,rr;
for(i=0;i<n;i++)
{
scanf("%d%d",&ll,&rr);
s[add].c=ll;
s[add].no=add;
add++;
s[add].c=rr;
s[add].no=add;
add++;
}

sort(&s[0],&s[add],cmp);

int dd=0;
s[0].temp=0;
for(i=1;i<add;i++)
{
if(s[i].c==s[i-1].c)
s[i].temp=dd;
else
{
dd++;
s[i].temp=dd;
}
}

sort(&s[0],&s[add],cmp1);
int j;
build(0,dd,1);
for(i=0;i<add;i+=2)
{
updata(s[i].temp,s[i+1].temp,1,1);
}



int max=0;
for(i=0;i<dd;i++)
{
if(search(i,i,1)>max)
max=search(i,i,1);
}
printf("%d\n",max);
}
}

更简单的方法
看了一下别人的解法,是优先队列

先按开始时间排序,在不断更新队列,同时记录队列什么时候最长就好了

View Code
#include<stdio.h>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;

struct data
{
int start,end;
}s[50009];

int cmp(data a,data b)
{
return a.start<b.start;
}

struct qq
{
friend bool operator<(qq a,qq b)
{
return a.end>b.end;
}
qq(int a)
{
end=a;
}
int end;
};

int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i;
for(i=0;i<n;i++)
{
scanf("%d%d",&s[i].start,&s[i].end);
}

sort(&s[0],&s[n],cmp);
int max=1;
priority_queue<qq> pq;

pq.push(qq(s[0].end));
for(i=1;i<n;i++)
{
while((!pq.empty())&&pq.top().end<s[i].start)
pq.pop();
pq.push(qq(s[i].end));
if(pq.size() > max)max=pq.size();
}

printf("%d\n",max);
}
}



你可能感兴趣的:(USACO)