雀巢咖啡杯模拟赛?!(一) 倍增啊倍增!!

来源:互联网 发布:淘宝店铺免费模板 编辑:程序博客网 时间:2024/04/29 02:29

    

       被 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.                                      


 

原创粉丝点击