最近屯题都忘了把解题报告写上了
这道题是一道比较烦的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. JavaScript高级程序设计(五): js的关键字instanceof和typeof使用

    JavaScript中instanceof和typeof 常用来判断一个变量是否为空,或者是什么类型的.但它们之间还是有区别的: 一.typeof 1.含义:typeof返回一个表达式的数据类型的字符 ...

  2. Java实战之01Struts2-05contextMAP、EL、OGNL

    十五.contextMap 1.动作类的生命周期 明确:动作类是多例的,每次动作访问,动作类都会实例化.所以是线程安全的.与Struts1的区别是,struts1的动作类是单例的. 2.请求动作的数据 ...

  3. 九度OJ 1434 今年暑假不AC

    题目地址:http://ac.jobdu.com/problem.php?pid=1434 题目描述: “今年暑假不AC?”“是的.”“那你干什么呢?”“看世界杯呀,笨蛋!”“@#$%^&*% ...

  4. Plugin 'FEDERATED' is disabled 或 1067错误 启动错误与“服务 mysql 意外停止”解决方法

    MYSQL启动报1067错误,系统日志中是“服务 mysql 意外停止” Mysql日志中则是:“Plugin 'FEDERATED' is disabled” 网我在网上找到解决方案:1.在MY.I ...

  5. linux 文件类型

    文件类型 1)windows中是以文件的扩展名来区分文件类型的 2)LINUX中文件扩展名和文件类型没有关系. 3)为了容易区分和兼容用户使用windows的习惯,我们也经常扩展名,但是在LINUX系 ...

  6. 【实习记】2014-09-04浏览代码查middle资料+总结我折腾过的源码浏览器

        浏览着代码,看源码可以先看make文件,make文件有制造的流程信息. 一般可以从运行的程序对应的cpp看起.然而如果有框架,那就不容易了,会关系错纵复杂. 总结一下我折腾过的源码阅读器. s ...

  7. [转]maven插件的开发

    原文链接: http://clojure.iteye.com/blog/1124188 另一篇文章 http://blog.csdn.net/csfreebird/article/details/77 ...

  8. thinkPHP add、save无法添加、修改不起作用

    案例:数据库新添加一字段,修改值不成功.解决方案:将Runtime/Data/_fields/下面的字段缓存删除,或者直接删除整个Runtime文件也是可以的分析:由于Thinkphp,采用字段缓存机 ...

  9. mysql添加超级管理员

    mysql>create user 'myroot'@'localhost' identified by 'myroot'; mysql>grant all privileges on * ...

  10. 以中断方式实现1s定时

    中断方式比较特殊,需要使用单片机内部的中断处理机制,同时指定中断函数. #include <reg52.h> sbit LED = P0^; unsigned ; void main() ...