• bzoj3091


    最近屯题都忘了把解题报告写上了
    这道题是一道比较烦的LCT,我们先考虑每个点上到底要维护什么
    我们设路径上有n个点,从起点到终点编号为1~n
    显然期望=S/[(n+1)n div 2]
    S=∑a[i]*i*(n-i+1) //这里理解一下
    =∑a[i]*[i*(n+1)-i*i]=(n+1)*∑a[i]*i-∑a[i]*i*i;
    考虑到找出x,y之间的路径就是把x,y路径上的点弄到一棵Auxiliary tree上
    对于每个点x,我们显然要维护以x为根的子树对应的序列的∑a[i]*i和∑a[i]*i*i,记为s2[x],s3[x]
    对于上面表达式的i,就是每个点在树(子树)上的名次
    下面的关键就是我们如何用其左右孩子的信息来维护父亲x,设l为x左孩子,r为x右孩子
    这里主要的影响在于对右孩子,原来右孩子的维护的是编号为1~size[r]的序列的s2[],s3[]
    现在我们加上去的是编号为size[l]+2~size[x]序列的s2[],s3[]
    我们考虑会会增加多少,对于s2 ∑a[i]*(i+p)-∑a[i]*i=p*∑a[i]
    对于s3 有∑a[i]*(i+p)^2-∑a[i]*i^2=∑a[i]*(2*p*i+p*p)=p*p*∑a[i]+2*p*∑a[i]*i
    这里维护就很显然了,我们还要再维护一个s1[]记录∑a[i]
    而修改相对比较简单,其实就是对s1,s2,s3分别加上d*n,d*∑i,d*∑i*i 这个直接上公式
    但这里还并没有完,我们用的LCT有个操作叫换根,而换根要翻转左右子树
    而这样左右子树的编号就反过来了,从而节点上记录s2[],s3[]就不正确了
    我的解决方法是再维护ss2[],ss3[],记录倒序编号时∑a[i]*i和∑a[i]*i*i
    然后要左右子树交换时,就交换ss2[],s2[]和ss3[]和s3[]
    具体实现细节见程序

      1 type node=record
      2        po,next:longint;
      3      end;
      4 
      5 var son:array[0..50010,1..2] of longint;
      6     p,a,q,fa,add,size:array[0..50010] of longint;
      7     s1,ss2,ss3,s2,s3:array[0..50010] of int64;
      8     rev:array[0..50010] of boolean;
      9     e:array[0..100010] of node;
     10     cc,t,len,ch,n,m,x,y,z,i:longint;
     11 
     12 function gcd(a,b:int64):int64;
     13   begin
     14     if b=0 then exit(a)
     15     else exit(gcd(b,a mod b));
     16   end;
     17 
     18 procedure build(x,y:longint);
     19   begin
     20     inc(len);
     21     e[len].po:=y;
     22     e[len].next:=p[x];
     23     p[x]:=len;
     24   end;
     25 
     26 procedure dfs(x:longint);
     27   var i,y:longint;
     28   begin
     29     i:=p[x];
     30     while i<>0 do
     31     begin
     32       y:=e[i].po;
     33       if fa[x]<>y then
     34       begin
     35         fa[y]:=x;
     36         dfs(y);
     37       end;
     38       i:=e[i].next;
     39     end;
     40   end;
     41 
     42 procedure swap(var a,b:int64);
     43   var c:int64;
     44   begin
     45     c:=a;
     46     a:=b;
     47     b:=c;
     48   end;
     49 
     50 procedure reverse(x:longint);  //如上述
     51   var p:longint;
     52   begin
     53     swap(ss2[x],s2[x]);
     54     swap(ss3[x],s3[x]);
     55     rev[x]:=not rev[x];
     56   end;
     57 
     58 function root(x:longint):boolean;
     59   begin
     60     exit((son[fa[x],1]<>x) and (son[fa[x],2]<>x));
     61   end;
     62 
     63 procedure calc(x,z:longint);
     64   var p,c,d:int64;
     65   begin
     66     inc(add[x],z);
     67     inc(a[x],z);
     68     p:=size[x];
     69     c:=int64(z)*(p+1)*p div 2;
     70     d:=int64(z)*(p+1)*p*(2*p+1) div 6;  //平方和公式
     71     s1[x]:=s1[x]+int64(z)*p;
     72     s2[x]:=s2[x]+c;
     73     s3[x]:=s3[x]+d;
     74     ss2[x]:=ss2[x]+c;
     75     ss3[x]:=ss3[x]+d;
     76   end;
     77 
     78 procedure update(x:longint);
     79   var l,r:longint;
     80       p,q:int64;
     81   begin
     82     l:=son[x,1];
     83     r:=son[x,2];
     84     size[x]:=size[l]+size[r]+1;
     85     p:=size[l]+1;  //正序编号
     86     q:=size[r]+1;  //反序标号
     87     s1[x]:=s1[l]+s1[r]+a[x];
     88     s2[x]:=s2[l]+int64(a[x])*p+s2[r]+s1[r]*p;
     89     s3[x]:=s3[l]+int64(a[x])*p*p+s3[r]+p*p*s1[r]+2*p*s2[r];
     90     ss2[x]:=ss2[r]+int64(a[x])*q+ss2[l]+s1[l]*q;
     91     ss3[x]:=ss3[r]+int64(a[x])*q*q+ss3[l]+q*q*s1[l]+2*q*ss2[l];
     92   end;
     93 
     94 procedure push(x:longint);
     95   var r:longint;
     96   begin
     97     if rev[x] then
     98     begin
     99       r:=son[x,1]; son[x,1]:=son[x,2]; son[x,2]:=r;
    100       if son[x,1]<>0 then reverse(son[x,1]);
    101       if son[x,2]<>0 then reverse(son[x,2]);
    102       rev[x]:=false;
    103     end;
    104     if add[x]<>0 then
    105     begin
    106       if son[x,1]<>0 then calc(son[x,1],add[x]);
    107       if son[x,2]<>0 then calc(son[x,2],add[x]);
    108       add[x]:=0;
    109     end;
    110   end;
    111 
    112 procedure rotate(x,w:longint);
    113   var y:longint;
    114   begin
    115     y:=fa[x];
    116     if not root(y) then
    117     begin
    118       if son[fa[y],1]=y then son[fa[y],1]:=x
    119       else son[fa[y],2]:=x;
    120     end;
    121     fa[x]:=fa[y];
    122     son[y,3-w]:=son[x,w];
    123     fa[son[x,w]]:=y;
    124     son[x,w]:=y;
    125     fa[y]:=x;
    126     update(y);
    127   end;
    128 
    129 procedure splay(x:longint);
    130   var i,y:longint;
    131       fl:boolean;
    132   begin
    133     t:=0;
    134     i:=x;
    135     while not root(i) do
    136     begin
    137       inc(t);
    138       q[t]:=i;
    139       i:=fa[i];
    140     end;
    141     inc(t);
    142     q[t]:=i;
    143     for i:=t downto 1 do
    144       push(q[i]);
    145     if t=1 then exit;
    146     fl:=true;
    147     while fl do
    148     begin
    149       y:=fa[x];
    150       if y=q[t] then
    151       begin
    152         if son[y,1]=x then rotate(x,2)
    153         else rotate(x,1);
    154         fl:=false;
    155       end
    156       else begin
    157         if fa[y]=q[t] then fl:=false;
    158         if son[fa[y],1]=y then
    159         begin
    160           if son[y,1]=x then rotate(y,2)
    161           else rotate(x,1);
    162           rotate(x,2);
    163         end
    164         else begin
    165           if son[y,1]=x then rotate(x,2)
    166           else rotate(y,1);
    167           rotate(x,1);
    168         end;
    169       end;
    170     end;
    171     update(x);
    172   end;
    173 
    174 procedure access(x:longint);
    175   var y:longint;
    176   begin
    177     y:=0;
    178     repeat
    179       splay(x);
    180       son[x,2]:=y;
    181       update(x);
    182       y:=x;
    183       x:=fa[x];
    184     until x=0;
    185   end;
    186 
    187 function find(x,y:longint):boolean;
    188   begin
    189     while son[y,1]<>0 do y:=son[y,1];  //Auxiliary tree最左的点即为所在树的根节点
    190     if y=x then exit(true) else exit(false);
    191   end;
    192 
    193 procedure makeroot(x:longint);
    194   begin
    195     access(x);
    196     splay(x);
    197     reverse(x);  //注意,在这WA了几次
    198   end;
    199 
    200 procedure path(x,y:longint);
    201   begin
    202     makeroot(x);
    203     access(y);
    204     splay(y);
    205   end;
    206 
    207 procedure link(x,y:longint);
    208   begin
    209     if cc=0 then exit;  //一点小优化,cc记录删掉的边数
    210     path(x,y);
    211     if not find(x,y) then
    212     begin
    213       fa[x]:=y;
    214       dec(cc);
    215     end;
    216   end;
    217 
    218 procedure cut(x,y:longint);
    219   begin
    220     path(x,y);
    221     if (son[y,1]=x) and (son[x,2]=0) then  //注意两点间有边的判定
    222     begin
    223       inc(cc);
    224       fa[x]:=0;
    225       son[y,1]:=0;
    226     end;
    227   end;
    228 
    229 procedure change(x,y,z:longint);
    230   begin
    231     path(x,y);
    232     if (cc=0) or find(x,y) then calc(y,z);
    233   end;
    234 
    235 procedure ask(x,y:longint);
    236   var a,b,c:int64;
    237   begin
    238     path(x,y);
    239     if (cc=0) or find(x,y) then
    240     begin
    241       c:=size[y];
    242       a:=(c+1)*s2[y]-s3[y];
    243       b:=c*(c+1) div 2;
    244       c:=gcd(a,b);
    245       writeln(a div c,'/',b div c);
    246     end
    247     else writeln(-1);
    248   end;
    249 
    250 begin
    251   readln(n,m);
    252   for i:=1 to n do
    253   begin
    254     read(a[i]);
    255     size[i]:=1;
    256   end;
    257   for i:=1 to n-1 do
    258   begin
    259     readln(x,y);
    260     build(x,y);
    261     build(y,x);
    262   end;
    263   dfs(1);  //这里先dfs构造树,如果直接link的话会TLE目测
    264   for i:=1 to m do
    265   begin
    266     read(ch,x,y);
    267     if ch=1 then
    268       cut(x,y)
    269     else if ch=2 then
    270       link(x,y)
    271     else if ch=4 then
    272       ask(x,y)
    273     else begin
    274       read(z);
    275       change(x,y,z);
    276     end;
    277     readln;
    278   end;
    279 end.
    View Code
  • 相关阅读:
    brewhome
    WIN7下安装SQL server 2008 R2“出现性能计数器注册表配置单元一致性”失败的解决办法(新)
    话说ELK使用安装,结合.NET Core、ABP框架Nlog日志
    支付系统架构
    高可用Redis服务架构分析与搭建
    基于STS和JWT的微服务身份认证
    全面解读NoSQL数据库Redis的核心技术与应用实践
    Redis应用及安装
    微服务实践分享与探讨
    Docker的核心概念,镜像操作
  • 原文地址:https://www.cnblogs.com/phile/p/4472987.html
Copyright © 2020-2023  润新知