最近屯题都忘了把解题报告写上了
这道题是一道比较烦的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. poj2299 二分思想

    poj2299   http://poj.org/problem?id=2299题意: 一个含有n个数的数组, 每次只能交换相邻的两个数, 求最少操作多少次可以使该数组变成一个有序数组(从小到大).  ...

  2. virtualbox安装ubuntu出现“The system is running in low-graphics mode”

    cd /etc/X11 sudo mv xorg.conf.failsafe xorg.conf sudo reboot 即可.

  3. 计算Android屏幕解锁组合数

    晚饭时和同事聊到安卓屏幕解锁时会有多少种解锁方案,觉得很有趣,吃完饭开始想办法解题,花了大概2个小时解决.思路如下: 使用索引值0-9表示从左到右.从上到下的9个点,行.列号很容易从索引值得到: 使用 ...

  4. 学习笔记_Java_day13_JSP三大指令()

    JSP指令 1        JSP指令概述 JSP指令的格式:<%@指令名 attr1=”” attr2=”” %>,一般都会把JSP指令放到JSP文件的最上方,但这不是必须的. JSP ...

  5. 一、VSTO概述

    一.什么是VSTO? VSTO = Visual Studo Tools for Office,是.net平台下的Office开发技术.相对于传统的VBA(Visual Basic Applicati ...

  6. "ERR_GFX_D3D_INIT", GTA5-报错解决办法

    GTA5 PC 版,online模式报错“ERR_GFX_D3D_INIT”. 网上搜到一篇文章,可以解决此问题: http://fixcrasheserrorguide.com/fix-grand- ...

  7. STL中map与hash_map的比较

    1. map : C++的STL中map是使用树来做查找算法; 时间复杂度:O(log2N) 2. hash_map : 使用hash表来排列配对,hash表是使用关键字来计算表位置; 时间复杂度:O ...

  8. mysql数据库导出时报错mysqldump: Got error: 145的解决方法

      在给mysql数据库备份时,报错:mysqldump: Got error: 145: Table './jxzhtopenfire/ofoffline' is marked as crashed ...

  9. 配置php连接apache

    配置php连接apache 1.安装php所需要的库 yum install zlib-devel libxml2-devel libjpeg-devel libjpeg-turbo-devel li ...

  10. tmux复制到windows剪贴板/粘贴板的坑

    以下所有操作都是在windows下面用putty连接linux centos6的情景下. 一直很纳闷为什么在tmux模式下不能把复制到的文字放到系统的粘贴板里面呢?通过层层阻碍,终于找到了原因. 去掉 ...