最近屯题都忘了把解题报告写上了
这道题是一道比较烦的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[]
具体实现细节见程序

 type node=record
po,next:longint;
end; var son:array[..,..] of longint;
p,a,q,fa,add,size:array[..] of longint;
s1,ss2,ss3,s2,s3:array[..] of int64;
rev:array[..] of boolean;
e:array[..] of node;
cc,t,len,ch,n,m,x,y,z,i:longint; function gcd(a,b:int64):int64;
begin
if b= then exit(a)
else exit(gcd(b,a mod b));
end; procedure build(x,y:longint);
begin
inc(len);
e[len].po:=y;
e[len].next:=p[x];
p[x]:=len;
end; procedure dfs(x:longint);
var i,y:longint;
begin
i:=p[x];
while i<> do
begin
y:=e[i].po;
if fa[x]<>y then
begin
fa[y]:=x;
dfs(y);
end;
i:=e[i].next;
end;
end; procedure swap(var a,b:int64);
var c:int64;
begin
c:=a;
a:=b;
b:=c;
end; procedure reverse(x:longint); //如上述
var p:longint;
begin
swap(ss2[x],s2[x]);
swap(ss3[x],s3[x]);
rev[x]:=not rev[x];
end; function root(x:longint):boolean;
begin
exit((son[fa[x],]<>x) and (son[fa[x],]<>x));
end; procedure calc(x,z:longint);
var p,c,d:int64;
begin
inc(add[x],z);
inc(a[x],z);
p:=size[x];
c:=int64(z)*(p+)*p div ;
d:=int64(z)*(p+)*p*(*p+) div ; //平方和公式
s1[x]:=s1[x]+int64(z)*p;
s2[x]:=s2[x]+c;
s3[x]:=s3[x]+d;
ss2[x]:=ss2[x]+c;
ss3[x]:=ss3[x]+d;
end; procedure update(x:longint);
var l,r:longint;
p,q:int64;
begin
l:=son[x,];
r:=son[x,];
size[x]:=size[l]+size[r]+;
p:=size[l]+; //正序编号
q:=size[r]+; //反序标号
s1[x]:=s1[l]+s1[r]+a[x];
s2[x]:=s2[l]+int64(a[x])*p+s2[r]+s1[r]*p;
s3[x]:=s3[l]+int64(a[x])*p*p+s3[r]+p*p*s1[r]+*p*s2[r];
ss2[x]:=ss2[r]+int64(a[x])*q+ss2[l]+s1[l]*q;
ss3[x]:=ss3[r]+int64(a[x])*q*q+ss3[l]+q*q*s1[l]+*q*ss2[l];
end; procedure push(x:longint);
var r:longint;
begin
if rev[x] then
begin
r:=son[x,]; son[x,]:=son[x,]; son[x,]:=r;
if son[x,]<> then reverse(son[x,]);
if son[x,]<> then reverse(son[x,]);
rev[x]:=false;
end;
if add[x]<> then
begin
if son[x,]<> then calc(son[x,],add[x]);
if son[x,]<> then calc(son[x,],add[x]);
add[x]:=;
end;
end; procedure rotate(x,w:longint);
var y:longint;
begin
y:=fa[x];
if not root(y) then
begin
if son[fa[y],]=y then son[fa[y],]:=x
else son[fa[y],]:=x;
end;
fa[x]:=fa[y];
son[y,-w]:=son[x,w];
fa[son[x,w]]:=y;
son[x,w]:=y;
fa[y]:=x;
update(y);
end; procedure splay(x:longint);
var i,y:longint;
fl:boolean;
begin
t:=;
i:=x;
while not root(i) do
begin
inc(t);
q[t]:=i;
i:=fa[i];
end;
inc(t);
q[t]:=i;
for i:=t downto do
push(q[i]);
if t= then exit;
fl:=true;
while fl do
begin
y:=fa[x];
if y=q[t] then
begin
if son[y,]=x then rotate(x,)
else rotate(x,);
fl:=false;
end
else begin
if fa[y]=q[t] then fl:=false;
if son[fa[y],]=y then
begin
if son[y,]=x then rotate(y,)
else rotate(x,);
rotate(x,);
end
else begin
if son[y,]=x then rotate(x,)
else rotate(y,);
rotate(x,);
end;
end;
end;
update(x);
end; procedure access(x:longint);
var y:longint;
begin
y:=;
repeat
splay(x);
son[x,]:=y;
update(x);
y:=x;
x:=fa[x];
until x=;
end; function find(x,y:longint):boolean;
begin
while son[y,]<> do y:=son[y,]; //Auxiliary tree最左的点即为所在树的根节点
if y=x then exit(true) else exit(false);
end; procedure makeroot(x:longint);
begin
access(x);
splay(x);
reverse(x); //注意,在这WA了几次
end; procedure path(x,y:longint);
begin
makeroot(x);
access(y);
splay(y);
end; procedure link(x,y:longint);
begin
if cc= then exit; //一点小优化,cc记录删掉的边数
path(x,y);
if not find(x,y) then
begin
fa[x]:=y;
dec(cc);
end;
end; procedure cut(x,y:longint);
begin
path(x,y);
if (son[y,]=x) and (son[x,]=) then //注意两点间有边的判定
begin
inc(cc);
fa[x]:=;
son[y,]:=;
end;
end; procedure change(x,y,z:longint);
begin
path(x,y);
if (cc=) or find(x,y) then calc(y,z);
end; procedure ask(x,y:longint);
var a,b,c:int64;
begin
path(x,y);
if (cc=) or find(x,y) then
begin
c:=size[y];
a:=(c+)*s2[y]-s3[y];
b:=c*(c+) div ;
c:=gcd(a,b);
writeln(a div c,'/',b div c);
end
else writeln(-);
end; begin
readln(n,m);
for i:= to n do
begin
read(a[i]);
size[i]:=;
end;
for i:= to n- do
begin
readln(x,y);
build(x,y);
build(y,x);
end;
dfs(); //这里先dfs构造树,如果直接link的话会TLE目测
for i:= to m do
begin
read(ch,x,y);
if ch= then
cut(x,y)
else if ch= then
link(x,y)
else if ch= then
ask(x,y)
else begin
read(z);
change(x,y,z);
end;
readln;
end;
end.

bzoj3091的更多相关文章

  1. BZOJ3091 城市旅行 LCT

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3091 题意概括 鉴于本人语文不好,此题的描述原题很清晰,废话不多,请看原题. 可怕,原题是图片,不 ...

  2. 【bzoj3091】 城市旅行

    http://www.lydsy.com/JudgeOnline/problem.php?id=3091 (题目链接) 题意 给出一棵无根树,维护四个操作.link,cut,路径加法,路径期望查询. ...

  3. 【BZOJ3091】城市旅行 LCT

    [BZOJ3091]城市旅行 Description Input Output Sample Input 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 ...

  4. BZOJ3091: 城市旅行

    Description Input Output Sample Input 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 1 4 1 4 Sample ...

  5. 【LCT】BZOJ3091 城市旅行

    3091: 城市旅行 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1927  Solved: 631[Submit][Status][Discuss ...

  6. BZOJ3091城市旅行——LCT区间信息合并

    题目描述 输入 输出 样例输入 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 1 4 1 4 样例输出 16/3 6/1 提示 对于所有数据满足 1& ...

  7. 【bzoj3091】城市旅行 LCT区间合并

    题目描述 输入 输出 样例输入 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 1 4 1 4 样例输出 16/3 6/1 题解 LCT区间合并 前三个 ...

  8. BZOJ3091: 城市旅行(LCT,数学期望)

    Description Input Output Sample Input 4 5 1 3 2 5 1 2 1 3 2 4 4 2 4 1 2 4 2 3 4 3 1 4 1 4 1 4 Sample ...

  9. bzoj3091 城市旅行 LCT + 区间合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3091 题解 调了整个晚自习才调出来的问题. 乍一看是个 LCT 板子题. 再看一眼还是个 LC ...

随机推荐

  1. 搭建Spring、Spring MVC、Mybatis和Freemarker

    搭建Spring.Spring MVC.Mybatis和Freemarker 1.pom文件 <project xmlns="http://maven.apache.org/POM/4 ...

  2. iOS开发——常用字符串string相关方法和处理

    (持续更新中……) 1,四舍五入 2,剔除字符 3,拼接字符 4,字符个数和长度 5,字符串的比较 6,字符串的范围 7,字符串转Number类型

  3. xcode插件安装完之后无法使用问题解决

    1.打开xcode插件所在的目录: 例如: ~/wangdi/library/Application Support/Developer/Shared/Xcode/Plug-ins /Users/su ...

  4. @Resource注解省略name属性后的行为

    @Resource有一个name属性,该属性值为所要注入的Bean实例的id,类似于<property.../>元素的ref属性,不过在spring中允许省略name属性值,省略后在以下情 ...

  5. identifier not found error on function call

    在C++工程中,自定义一个方法 void fgetsDemo(),在main 方法中调用,源代码如下: #include "stdafx.h" #include <stdio ...

  6. As3 里的正则相关

    用正则的时候 不要用if(content.match("test").length > 0) ...; 改成 if(content.match(/test/g).length ...

  7. Python3 高级特性

    切片 L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3.即索引0,1,2,正好是3个元素. 如果第一个索引是0,还可以省略: >>> L =['Michael', ' ...

  8. Gitlab服务器搭建(For fedora23)

    1. Install and configure the necessary dependencies sudo yum install curl policycoreutils openssh-se ...

  9. 『奇葩问题集锦』function * (next){ 执行报错 SyntaxError: Unexpected token *

    这是因为  app.use(function * (){ 语句中有一个 * ,这种方式被称为generator functions ,一般写作function *(){...} 的形式,在此类func ...

  10. margin系列之内秀篇(二)

    本系列摘自  飘零雾雨的博客 可挖掘性 之前已经写过一篇关于 margin 应用场景的文章:margin系列之内秀篇,当然,它的应用场景会远大于文中所述,无法一一列举. 所以本篇权当是对此的补遗好了, ...