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[]
具体实现细节见程序
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的更多相关文章
- BZOJ3091 城市旅行 LCT
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3091 题意概括 鉴于本人语文不好,此题的描述原题很清晰,废话不多,请看原题. 可怕,原题是图片,不 ...
- 【bzoj3091】 城市旅行
http://www.lydsy.com/JudgeOnline/problem.php?id=3091 (题目链接) 题意 给出一棵无根树,维护四个操作.link,cut,路径加法,路径期望查询. ...
- 【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 ...
- 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 ...
- 【LCT】BZOJ3091 城市旅行
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1927 Solved: 631[Submit][Status][Discuss ...
- 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& ...
- 【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区间合并 前三个 ...
- 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 ...
- bzoj3091 城市旅行 LCT + 区间合并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3091 题解 调了整个晚自习才调出来的问题. 乍一看是个 LCT 板子题. 再看一眼还是个 LC ...
随机推荐
- Webservice学习之——即时发布与定制发布
一.工具 myEclipse tomcat 6.0 以上版本 axis-bin-1_4.zip 二.即时发布 1.解压 axis-bin-1_4.zip 2.axis-bin-1_4.zip\axi ...
- ORACLE 11g R2数据库安装硬件环境要求
物理内存要求:最小1G,在windows7,windows8,windows8.1上最小2G. 虚拟内存(或分页空间)容量要求: Available RAM Swap Space Required B ...
- 7-2 DBA顾问第一次上次操作考试
SQLPLUS执行: 1--@?/rdbms/admin/awrrpt 生产snapshot, 一个时间点, 再执行下一个时间点. 2-- 附件作业第一次执行步骤: 1) SQLP ...
- 09_Mybatis开发Dao方法——mapper代理开发规范
一.开发规范 需要编写mapper.xml映射文件(本项目为userMapper.xml,类似于前面的user.xml). 编写mapper接口需要遵循一些开发规范,这样MyBatis可以自动生成ma ...
- IOS 学习笔记 2015-03-24 OC-API-网络访问-案例一
// // WPSuggest.h // OC-API-网络访问 // // Created by wangtouwang on 15/3/24. // Copyright (c) 2015年 wan ...
- Java Servlet 回顾
一.转发请求RequestDispatcher 使用request域对象把数据带给转发资源,与重定向的区别:客户端只发出一次请求,服务器端调用多个资源,客户端浏览器地址栏没改变:转发是一次请求,使用的 ...
- ubuntu 初始
1.命令行界面与图形界面 ctrl + alt + f1进入命令行界面 ctrl + alt + f7 切换图形界面 2.ubuntu 的wubi安装与卸载 第一:在win 系统下启动DOS,进入命令 ...
- hdu-A+B问题,大数加法
格式问题很头疼啊 Input The first line of the input contains an integer T(1<=T<=20) which means the num ...
- Swift lazy 修饰符和方法
LAZY 修饰符和 LAZY 方法 由 王巍 (@ONEVCAT) 发布于 2015/10/07 延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间 ...
- STM32固件库
一.STM32固件库开发和传统寄存器开发方式的区别 二.CMSIS标准 CMSIS标准--Cortex Microcontroller Software Interface Standard,是ARM ...