雀巢咖啡杯模擬賽?!(一) 倍增啊倍增!!

    

       被 poj 的數據坑住了,於是乎想到了這個N久沒有寫的博客了。

       前兩天被用來當做是NOIP 模擬題的............雀巢咖啡杯模擬賽題.....(@ . @),考的是相當的萎 ,就當積攢rp,明天爆發吧。

    

        第一天的題目,第一題相當坑人,就是求最大子段積,結果被騙寫高精(!。!),寫的太醜了,而實際上謝老師挑選的數據水,最後打裸就行了.........

        第二題,無語的貪心,被altman 用微元法解釋(=.=),加上邊界特判,對的無比詭異.......

        

  ============================================ 以上都是廢話==============================================

   

        感覺第三題倍增的思想滿喜歡的,題意是給定一個有向圖,其中每個節點都有k 條出邊,爲其編號1~k(K<=26),每條邊附帶權值。然後給定一串行走指令:假設你初始在1點,給你100000 個操作   Ai  ,Ci, 表示沿着標號爲Ai的邊走Ci次,讓你執行這些操作,並記錄經過的邊的邊權和。 Ci 有10^9級別。

       考場上其實看完題目後就感覺到是倍增之類的東西,但是當時被第一題坑了,寫完第一題只有半個小時了(而且第一題還寫錯了~.~),就沒有去想了,當然,就算想了可能也編不出,因爲,其實還沒有編過倍增。

         .......

       

      於是乎後來發現倍增是多麼美妙,多麼好寫........

       就這道題而言,就是預處理從第i 個節點 沿第j 種邊走 2^k條邊的情況,最後用預處理的數組裸算就可以了。

       反正就是非常神奇的用了二進制,二進制真神奇(忽略我賣萌.........)


       於是去寫了lca 的nlogn 的倍增算法,話說至今還沒有寫過倍增lca(其實貌似tanjan lca也沒寫幾次,應該被鄙視!.!);

       貼個代碼吧:::::

  

program  poj1330;
var
     l,sum,next,d:array[0..30000]of longint;
     g:array[0..10000+10]of boolean;
     k,t,top,i,j,n,m,x,y,dx:longint;
     f:array[0..10000+10,0..15] of longint;
procedure inf;
begin
   assign(input,'1330.in');
   assign(output,'1330.out');
   reset(input);rewrite(output);
end;
procedure ouf;
begin
   close(input);close(output);
end;
procedure origin;
begin
    fillchar(l,sizeof(l),0);
    fillchar(next,sizeof(next),0);
    fillchar(sum,sizeof(sum),0);
    fillchar(f,sizeof(f),0);
    fillchar(g,sizeof(g),false);
    top:=0;
end;
procedure dfs(rt,x,low:longint);
var k:longint;
begin
     k:=l[x];  f[x,0]:=rt;  d[x]:=low;
     if low>m then m:=low;
     while k<>0 do
      begin
        if sum[k]<>rt then dfs(x,sum[k],low+1);
        k:=next[k];
      end;
end;
procedure link(x,y:longint);
begin
     inc(top);
     next[top]:=l[x];
     l[x]:=top;
     sum[top]:=y;
end;
procedure init;
begin
    read(n); origin;
    for i:=1 to n-1 do
        begin
           read(x,y); g[y]:=true;
           link(x,y);
        end;
    for i:=1 to n do
    if g[i]=false then dfs(0,i,1);
    for j:=1 to trunc(ln(m)/ln(2))  do
      for i:=1 to n do
          f[i,j]:=f[f[i,j-1],j-1];
    read(x,y);
end;

procedure main;
begin
     if d[x]<d[y] then begin dx:=x; x:=y; y:=dx; end;
     dx:=d[x]-d[y];
     if dx>0 then
     for i:=0 to trunc(ln(dx)/ln(2)) do
         if (dx shr i) and 1=1 then
            x:=f[x,i];
     k:=0;
     while x<>y do
      begin
        if (f[x,k]<>f[y,k])  or ((f[x,k]=f[y,k])  and (k=0)) then
         begin
           x:=f[x,k]; y:=f[y,k];
           inc(k);
         end
        else dec(k);
      end;
     writeln(x);
end;

begin
  // inf;
   read(t);
   for t:=1 to t do
     begin
      init;
      main;
     end;
  // ouf;
end.                   

寫的很醜(不說也發現了.........)

總之就是首先預處理f【i,k】,即i節點往上延伸2^k 層的父親,然後先用這個數組把詢問的x,y 提到相同高度,

 if d[x]<d[y] then begin dx:=x; x:=y; y:=dx; end;
     dx:=d[x]-d[y];
     if dx>0 then
     for i:=0 to trunc(ln(dx)/ln(2)) do
         if (dx shr i) and 1=1 then
            x:=f[x,i];

然後再利用貌似二分一樣的東西:

對於同一深度的x,y,如果f【x,k】<>f【x,k】,說明k還不夠大,lca還在f【x,k】上;

                                         ****f 【x,k】= f【x,k】,說明k夠大了,應該適當減小k

 k:=0;
     while x<>y do
      begin
        if (f[x,k]<>f[y,k])  or ((f[x,k]=f[y,k])  and (k=0)) then
         begin
           x:=f[x,k]; y:=f[y,k];
           inc(k);
         end
        else dec(k);
      end;

就這樣了.............


順便寫了tarjan lca:

program ex1330_tarjan;
var
  fa:array[0..20000]of longint;
  g:array[0..20000]of boolean;
  l,sum,next:array[0..30000]of longint;
  x,y,i,n,ans,t,top,k:longint;
procedure inf;
begin
   assign(input,'1330.in');
   assign(output,'1330.out');
   reset(input);rewrite(output);
end;
procedure ouf;
begin
   close(input);close(output);
end;
procedure link(x,y:longint);
begin
     inc(top);
     next[top]:=l[x];
     l[x]:=top;
     sum[top]:=y;
end;
procedure origin;
begin
    fillchar(l,sizeof(l),0);
    fillchar(next,sizeof(next),0);
    fillchar(sum,sizeof(sum),0);
    fillchar(g,sizeof(g),false);
    for i:=1 to n do fa[i]:=i;
    top:=0;
end;
procedure init;
begin
    read(n);
    origin;
    for i:=1 to n-1 do
      begin
        read(x,y); g[y]:=true;
        link(x,y);
      end;
    for i:=1 to n do
     if g[i]=false then k:=i;
    fillchar(g,sizeof(g),false);
    read(x,y);
end;
function find(x:longint):longint;
begin
  if fa[x]<>x then fa[x]:=find(fa[x]);
  exit(fa[x]);
end;
procedure dfs(rt:longint);
var k:longint;
begin
   if rt=5 then
     rt:=rt;
   k:=l[rt]; g[rt]:=true;
   if rt=x then if g[y] then ans:=find(y);
   if rt=y then if g[x] then ans:=find(X);
   while k<>0 do
     begin
       dfs(sum[k]);
       fa[sum[k]]:=rt;
       k:=next[k];
     end;
end;
begin
  // inf;
   read(t);
   for t:=1 to t do
     begin
       init;
       dfs(k);
       writeln(ans);
     end;
   //ouf;
end.                                      


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章