poj 2528 Mayor's posters

http://poj.org/problem?id=2528

题目大意:有一面被划分成n格的墙,依次停入m两车,每辆车占据第l[i]~r[i]格的墙。问最后能看到几辆车。有多组数据。

 

线段树+离散。每次停车用不同的值覆盖一段给定区间,最后统计整段上不同的值有多少即为所求。

 

一开始抱着侥幸心理直接上线段树,结果MLE。。。

接下来又WA了两次。

第一次是没考虑下面这种情况:

1

3

1 10

1 3

6

答案应该是3,但是在离散的时候要是没有在3和5之间多插入一个点,就会处理成第2,3辆车把第一辆覆盖掉了。

第二次是数组开小了。因为离散的时候有多加入一些点,肯定要占用额外的空间,不过我已经开到8n的大小了还超。。。最后蛮试着开了16W居然给过了。。

 

AC CODE

 

program pku_2528;
var a:array[1..160000] of longint;
    p:array[1..160000] of boolean;
    l,r:array[1..20000] of longint;
    b,c:array[1..40000] of longint;
    q:array[1..20000] of boolean;    //每个数组都开大了一倍。依然不懂哪里小了。。。
    x,ans,tot,i,s,t,n,tmp:longint;
//============================================================================
procedure ins(be,en,now:longint);
var mid:longint;
begin
  if (s<=be) and (t>=en) then
  begin
    a[now]:=x; p[now]:=true;
    exit;
  end;
  if p[now] then    //要记住向下推标记、
  begin
    a[now shl 1]:=a[now]; a[now shl 1+1]:=a[now];
    p[now shl 1]:=true; p[now shl 1+1]:=true;
    p[now]:=false;
  end; mid:=(be+en) shr 1;
  if s<=mid then ins(be,mid,now shl 1);
  if t>mid then ins(mid+1,en,now shl 1+1);
  a[now]:=x;
end;
//============================================================================
procedure ask(now:longint);
begin
  if p[now] then
  begin
    if not(q[a[now]]) then
    begin
      q[a[now]]:=true;
      inc(ans);
    end; exit;
  end;
  if a[now shl 1]<>0 then ask(now shl 1);
  if a[now shl 1+1]<>0 then ask(now shl 1+1);
end;
//============================================================================
procedure qsort(s,t:longint);
var k,i,j,tt:longint;
begin
  k:=b[(s+t) shr 1]; i:=s; j:=t;
  repeat
    while b[i]<k do inc(i);
    while b[j]>k do dec(j);    //快排这里一开始还编错了。。。不能用b[i]<=k、、、
    if i<=j then
    begin
      tt:=b[i]; b[i]:=b[j]; b[j]:=tt;
      tt:=c[i]; c[i]:=c[j]; c[j]:=tt;
      inc(i); dec(j);
    end;
  until i>j;
  if j>s then qsort(s,j);
  if i<t then qsort(i,t);
end;
//============================================================================
procedure lisan;
var i:longint;
begin
  for i:=1 to n do b[i*2-1]:=l[i];
  for i:=1 to n do b[i*2]:=r[i];
  for i:=1 to n do c[i*2-1]:=i;
  for i:=1 to n do c[i*2]:=i;
  qsort(1,2*n); tmp:=1; l[c[1]]:=1;
  for i:=2 to 2*n do
  begin
    if (i>1) and (b[i]>b[i-1]+1) then inc(tmp);
    if b[i]<>b[i-1] then inc(tmp);         //一开始相同的点没有合并。。。
    if r[c[i]]=b[i] then r[c[i]]:=tmp else l[c[i]]:=tmp;

  end;
end;
//============================================================================
procedure main;
var i:longint;
begin
  fillchar(a,sizeof(a),0);
  fillchar(p,sizeof(p),0);
  fillchar(q,sizeof(q),0);
  readln(n);
  for i:=1 to n do
    readln(l[i],r[i]);
  lisan;
  for x:=1 to n do
  begin
    s:=l[x]; t:=r[x];
    ins(1,tmp,1);
  end;
  ans:=0; ask(1);
  writeln(ans);
end;
//============================================================================
begin
  readln(tot);
  for i:=1 to tot do
    main;
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值