Помощь - Поиск - Пользователи - Календарь
Полная версия: Задача про точки и отрезки
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
c-ch
Точки и отрезки
(Время: 2 сек. Память: 16 Мб Сложность: 62%)
Дано N отрезков на числовой прямой и M точек на этой же прямой. Для каждой из данных точек определите, скольким отрезкам она принадлежит. Точка x считается принадлежащей отрезку с концами a и b, если выполняется двойное неравенство min(a, b) <= x <= max(a, b).

Входные данные

Первая строка входного файла INPUT.TXT содержит два целых числа N – число отрезков и M – число точек (1 <= N, M <= 10^5). В следующих N строках по два целых числа ai и bi – координаты концов соответствующего отрезка. В последней строке M целых чисел – координаты точек. Все числа во входном файле не превосходят по модулю 10^9.

Выходные данные

В выходной файл OUTPUT.TXT выведите M чисел – для каждой точки количество отрезков, в которых она содержится.

ПРИМЕРЫ
3 2
0 5
-3 2
7 10
1 6
ответ 2 0

1 3
-10 10
-100 100 0
ответ 0 0 1

Моя идея проста: сначала сортируем точки по координате, затем точки с одинаковой координатой сортируем по типу
К сожалению, этот вариант не проходит автоматическую систему проверки по времени (~+0,5сек) sad.gif
Самого теста у меня нет
Вероятно, надо прикрутить упорядочивание по типу точки в процедуру сортировки по координате, но я не представляю, как это сделать...
А может ещё какой-то вариант есть?
Времени у меня как всегда впритык unsure.gif

program Project1;

type
  tip=(_left,_none,_right);
  point=record x,n,c:longint; t:tip end;
  mas=array [1..300000]of point;
var
  a,b:mas;
  f:text;
  i,n,m,k,j:longint;
  t:point;

procedure quicksort(var a: mas; Lo,Hi: integer);
  procedure sort(l,r: integer);
  var
    i,j: integer;
    x,y:point;
  begin
    i:=l; j:=r;  x := a[(r+l) div 2];
    repeat
      while a[i].x<x.x do i:=i+1; 
      while x.x<a[j].x do j:=j-1; 
      if i<=j then
      begin
        if a[i].x > a[j].x then 
        begin
          y:=a[i]; a[i]:=a[j]; a[j]:=y
        end;
        i:=i+1; j:=j-1
      end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r)
  end; 
begin 
  sort(Lo,Hi)
end; 

procedure Tquicksort(var a: mas; Lo,Hi: integer);
  procedure sort(l,r: integer);
  var
    i,j: integer;
    x,y:point;
  begin
    i:=l; j:=r;  x := a[(r+l) div 2];
    repeat
      while a[i].t<x.t do i:=i+1; 
      while x.t<a[j].t do j:=j-1; 
      if i<=j then
      begin
        if a[i].t > a[j].t then 
        begin
          y:=a[i]; a[i]:=a[j]; a[j]:=y
        end;
        i:=i+1; j:=j-1
      end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r)
  end; 
begin 
  sort(Lo,Hi)
end; 

begin
assign(f,'input.txt');
reset(f);
readln(f,n,m);
k:=1;
for I := 1 to n do {читаем отрезки}
    begin
    readln(f,a[k].x,a[k+1].x);
    a[k].t:=_left; a[k+1].t:=_right;
    inc(k,2)
    end;
for I := 1 to m do {читаем точки}
  begin
  read(f,a[k].x);
  a[k].t:=_none;
  a[k].n:=i;
  inc(k)
  end;
close(f);
quicksort(a,1,k-1); {сортируем все точки по координате}
for i := 1 to k - 2 do
  if a[i].x=a[i+1].x then {находим последовательность точек с одинаковой координатой...}
    begin
    j:=i+1;
    while a[i].x=a[j].x do
      inc(j);
    tquicksort(a,i,j-1) {...и сортируем её по типу: сначала должны идти _left, затем _none, затем _right}
    end;
j:=0;
for I := 1 to k-1 do {считаем количество вхождений точки в отрезки}
  case a[i].t of
  _none:begin a[i].c:=j; b[a[i].n]:=a[i] end;
  _left:inc(j);
  _right:dec(j)
  end;
assign(f,'output.txt');
rewrite(f);
for i := 1 to m do
  if b[i].n>0 then write(f,b[i].c,' ');
close(f)
end.

Заранее спасибо
c-ch
ещё один вариант сделал: разводим начала и концы отрезков в разные массивы, оба упорядичиваем и для каждой точки бинарным поиском ищем сколько начал отрезков левее её (не строго) и сколько правее (строго). Их разность является ответом.
Вроде и сортировка и поиск достаточно быстрые, но всё равно по времени не укладывается sad.gif
program Project1;
uses math;
type arrtype=array[1..100000]of longint;
var
  l,r,p:arrtype;
  i,j,n,m,t1,t2:longint;
  f:text;

Procedure quicksort(Var ar: arrType; n: integer);
  Procedure sort(m, l: Integer);
  Var i, j, x, w: Integer;
  Begin
    i := m; j := l;
    x := ar[(m+l) div 2];
    Repeat
      While ar[i] < x Do Inc(i);
      While ar[j] > x Do Dec(j);
      If i <= j Then Begin
        w := ar[i]; ar[i] := ar[j]; ar[j] := w;
        Inc(i); Dec(j)
      End
    Until i > j;
    If m < j Then Sort(m, j);
    If i < l Then Sort(i, l)
  End;
Begin
  sort(1, n)
End;

function FindIt(x:longint):longint;

  function FindInLeft:longint;
  var left,right,middle:longint;
  begin
  if x<l[1] then result:=0
  else
  if x>l[n] then result:=n
  else
    begin
    left:=1; right:=n;
    repeat
    middle:=(right+left) div 2;
    if l[middle]>x then right:=middle
    else
    if l[middle]<x then left:=middle
    until (l[middle]<=x)or(right-left=1);
    while (l[middle]<=x)and(middle<=n) do inc(middle);
    result:=middle-1;
    end;
  end;

  function FindInRight:longint;
  var left,right,middle:longint;
  begin
  if x<r[1] then result:=0
  else
  if x>r[n] then result:=n
  else
    begin
    left:=1; right:=n;
    repeat
    middle:=(right+left) div 2;
    if r[middle]>x then right:=middle
    else
    if r[middle]<x then left:=middle
    until (r[middle]<=x)or(right-left=1);
    while (r[middle]>=x)and(middle<=n) do dec(middle);
      result:=middle;
    end;
  end;

begin
result:=abs(findinleft-findinright)
end;

begin
assign(f,'input.txt');
reset(f);
readln(f,n,m);
for i := 1 to n do
  begin
  readln(f,t1,t2);
  l[i]:=min(t1,t2);
  r[i]:=max(t1,t2);
  end;
for I := 1 to m do read(f,p[i]);
close(f);
quicksort(l,n);
quicksort(r,n);
assign(f,'output.txt');
rewrite(f);
for I := 1 to m do write(f,findit(p[i]),' ');
close(f);
end.

Lapp
Цитата(c-ch @ 5.04.2009 20:59) *
Вроде и сортировка и поиск достаточно быстрые, но всё равно по времени не укладывается
Я бы на твоем месте больше заботился о качестве самого кода. Например, вот тут:
  l[i]:=min(t1,t2);
  r[i]:=max(t1,t2);
- ты транжиришь время как будто у тебя есть вечность smile.gif
c-ch
конкретно этот кусок я исправил ветвлением, спасибо smile.gif
но толку-то никакого
либо есть что-то ещё, что я не вижу, либо одно из двух, как в анекдоте... smile.gif
volvo
c-ch
Насколько я вижу, у тебя вся проблема - в реализации бинарного поиска. Ты выбрал, наверное, самый неэффективный способ. Попробуй вот так:
function FindIt(x:longint):longint;
  function FindInLeft:longint;
  var left,right,middle:longint;
  begin
    if x<l[1] then result:=0
    else
      if x>l[n] then result:=n
      else begin
        left:=1; right:=n;
        (*
        repeat
          middle:=(right+left) div 2;
          if l[middle]>x then right:=middle
          else
            if l[middle]<x then left:=middle
        until (l[middle]<=x)or(right-left=1);
        *)
        while right-left > 1 do begin
          middle := (right+left) div 2;
          if l[middle] < x then left := middle
          else right := middle;
        end;
        while (l[middle]<=x)and(middle<=n) do inc(middle);
        result:=middle-1;
      end;
  end;

  function FindInRight:longint;
  var left,right,middle:longint;
  begin
    if x<r[1] then result:=0
    else
      if x>r[n] then result:=n
      else begin
        left:=1; right:=n;
        (*
        repeat
          middle:=(right+left) div 2;
          if r[middle]>x then right:=middle
          else
            if r[middle]<x then left:=middle
        until (r[middle]<=x)or(right-left=1);
        *)
        while right-left > 1 do begin
          middle := (right+left) div 2;
          if r[middle] < x then left := middle
          else right := middle;
        end;
        while (r[middle]>=x)and(middle<=n) do dec(middle);
        result:=middle;
      end;
    end;

begin
  result:=abs(findinleft-findinright)
end;
Казалось бы, ничего не изменилось, ан нет... smile.gif
c-ch
время улучшилось на пару сотых секунды smile.gif
но этого мало sad.gif
я уже начинаю подозревать систему проверки blink.gif
хотя, люди как-то сдают...то ли лыжи не едут...
volvo
Цитата
время улучшилось на пару сотых секунды
Да? У меня время уменьшилось с 8 секунд изначальных (n = m = 105, случайные данные) до 0.06 сек после внесения изменений... Что-то у тебя не то происходит...
c-ch
я лишь привёл цифры, которые дала система проверки...
буду дальше думать
passat
Координаты отрезков записываем в массив. Держим вспомогательный признак: начало отрезка +1, конец -1. Сортируем массив. Сортируем массив точек. Дольше идем от наименьшего в двух массивах. Сумма +1 будет давать количетво отрезков, которым принадлежит точка.

Такой алгоритм подойдет?
passat
Точнее, даже так. Все сливаем в один массив. ВВодим признаки: +1 - начало отрезка, 0 - точка, -1 - конец отрезка. Сортируем массив. Далее идем от начала к концу и подсчитываем суммы +1, -1, и 0. На каждом нуле запоминаем сумму.

Работать должно за время сортировки плюс полного прохода по массиву, т.е. O((2*N+M)*(1+log(2*N+M)))

Несколько ускорить может внутренняя проверка на исчерпанность точек и отрезков.

Сработает?
c-ch
конечно smile.gif
в первом посте именно такой вариант smile.gif
кстати, оба варианта показывают одинаковое время
может таки это не мой косяк?
volvo
Цитата
может таки это не мой косяк?
Может, ты все-таки дашь ссылку на сервер, на котором проверяешь код? А то борьба, похоже, идет с ветряными мельницами...

Ну, сгенерируй файл данных для макс. значений M, N и запусти у себя на машине твой второй и мой исправленный варианты решения. Сколько времени выполняется исправленный? Как может сервер выдавать тебе овертайм при разрешенном времени = 2 секунды (если он, конечно, вменяемый сервер)?
c-ch
пожалуйста: http://acmp.ru/index.asp?main=task&id_task=396
volvo
Я ничего с этим сервером не понимаю wacko.gif Была вот такая идея:

{$r-}
{$q-}
program Project1;
// uses windows;
const
  count = 100000;
type
  tevent = (ev_add, ev_check, ev_remove);
  trec = record
    ev: tevent;
    index: longint;
    X: longint;
  end;

  ev_array = array[1 .. 3 * count] of trec;
  arrtype = array[1 .. count] of longint;

var
  events: ev_array;


procedure quicksort(var a: ev_array; Lo,Hi: integer);
  function less(f, s: trec): boolean;
  begin
    less := (f.X < s.X) or ((f.X = s.X) and (f.ev < s.ev));
  end;
  function more(f, s: trec): boolean;
  begin
    more := (f.X > s.X) or ((f.X = s.X) and (f.ev > s.ev));
  end;
  procedure sort(l,r: integer);
  var
    i,j: integer;
    x,y: trec;
  begin
    i:=l; j:=r;  x := a[(r+l) div 2];
    repeat
      while less(a[i], x) do i:=i+1;
      while less(x, a[j]) do j:=j-1;
      if i<=j then
      begin
        if more(a[i], a[j]) then
        begin
          y:=a[i]; a[i]:=a[j]; a[j]:=y
        end;
        i:=i+1; j:=j-1
      end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r)
  end;
begin
  sort(Lo,Hi)
end;

// var tt: dword;
var
  f, fout: text;

  m, n, i, j: longint;
  cnt: arrtype;
  curr: longint;
  p, L, R: longint;

begin
  // tt := gettickcount;
  assign(f, 'input.txt'); reset(f);
  readln(f, n, m);
  j := 0;
  for i := 1 to n do begin
    readln(f, L, R);
    inc(j);
    events[j].ev := ev_add; events[j].index := -1; events[j].X := L;
    inc(j);
    events[j].ev := ev_remove; events[j].index := -1; events[j].X := R;
  end;

  for i := 1 to m do begin
    read(f, p);
    inc(j);
    events[j].ev := ev_check; events[j].index := i; events[j].X := p;
  end;
  quicksort(events, 1, j);
  close(f);

  curr := 0;
  for i := 1 to j do begin
    if events[i].ev = ev_add then inc(curr)
    else
      if events[i].ev = ev_check then cnt[events[i].index] := curr
      else dec(curr);
  end;

  assign(fout, 'output.txt'); rewrite(fout);
  for i := 1 to m do write(fout, cnt[i], ' ');
  close(fout);
  // writeln('time = ', gettickcount - tt);
end.
, 5 тестов отработало "влёт", на шестом с какого-то перепуга "неверный ответ", хотя что там может быть неверного? Может, ты найдешь ошибку в алгоритме?
volvo
Бррр... Да, сам виноват, посчитал, что в паре координат, образующих отрезок, всегда первой идет левая граница, а второй - правая. В условии этого не было указано, так что надо проверять, что меньше, а что - больше. С проверкой программа проходит все тесты, еще и с запасом...

c-ch, в алгоритме разобрался?
c-ch
да, спасибо :смайлик_с_пивом:
finasteride tablets 5mg where to
Statutaria Kamagra Vendite
azithromycin 500mg next day deli
Comprar Cialis Generico Por Internet
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.