题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=3091

题解

调了整个晚自习才调出来的问题。


乍一看是个 LCT 板子题。

再看一眼还是个 LCT 板子题,不过需要考虑两个区间的结果的合并。

首先考虑到期望可以转化为每一个区间的权值和。那么对于每一个区间,我们维护一个 \(s, ls, rs, sum\) 分别表示整个区间的和,所有前缀的和,所有后缀的和,整个区间的子区间权值和。

那么在区间合并的时候,\(rs\) 会被计算右区间大小次,\(ls\) 会被计算左区间大小次,直接合并就可以了。

合并出 \(ls, rs\) 的时候考虑每一个区间的值的变化即可。


还有一个东西是加标记 \(k\) 对一个区间的影响。设区间长度为 \(len\)。

这个标记对 \(ls, rs\) 的影响很显然,就是每一个前缀的长度和 \(\cdot k\),即 $\frac{len(len+1)k}2 $。

对于 \(sum\) 的影响是所有子区间长度之和。可以从每一个长度的区间数量来求,过程中式子比较繁琐,只给出答案:\(\frac{len(len+1)(len+2)k}6\)。


注意:

  1. \(ls, rs, sum\) 一类东西太多,不要搞混;
  2. 不连通时不要操作!!!不连通时不要操作!!!不连通时不要操作!!!

时间复杂度 \(O(m\log n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 50000 + 7; #define lc c[0]
#define rc c[1] int n, m;
int a[N]; struct Node {
int c[2], fa, rev, sz, v, add;
ll s, sum, ls, rs;
} t[N];
int st[N];
inline bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
inline bool idtfy(int o) { return t[t[o].fa].rc == o; }
inline void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
inline Node add_tag(Node a, int k) {
a.v += k, a.add += k;
a.s += (ll)k * a.sz;
a.sum += (ll)a.sz * (a.sz + 1) * (a.sz + 2) / 6 * k;
a.ls += (ll)a.sz * (a.sz + 1) / 2 * k;
a.rs += (ll)a.sz * (a.sz + 1) / 2 * k;
return a;
}
inline void pushup(int o) {
assert(!t[o].rev && !t[o].add);
const Node &tl = t[t[o].lc], &tr = t[t[o].rc];
t[o].sz = tl.sz + tr.sz + 1;
t[o].s = tl.s + tr.s + t[o].v;
t[o].ls = tl.ls + (tl.s + t[o].v) * (tr.sz + 1) + tr.ls;
t[o].rs = tr.rs + (tr.s + t[o].v) * (tl.sz + 1) + tl.rs;
t[o].sum = tl.sum + tr.sum + (ll)t[o].v * (tl.sz + 1) * (tr.sz + 1) + tl.rs * (tr.sz + 1) + tr.ls * (tl.sz + 1);
}
inline void pushdown(int o) {
if (t[o].rev) {
if (t[o].lc) t[t[o].lc].rev ^= 1, std::swap(t[t[o].lc].lc, t[t[o].lc].rc), std::swap(t[t[o].lc].ls, t[t[o].lc].rs);
if (t[o].rc) t[t[o].rc].rev ^= 1, std::swap(t[t[o].rc].lc, t[t[o].rc].rc), std::swap(t[t[o].rc].ls, t[t[o].rc].rs);
t[o].rev = 0;
}
if (t[o].add) {
if (t[o].lc) t[t[o].lc] = add_tag(t[t[o].lc], t[o].add);
if (t[o].rc) t[t[o].rc] = add_tag(t[t[o].rc], t[o].add);
t[o].add = 0;
}
}
inline void rotate(int o) {
int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
if (!isroot(fa)) t[pa].c[d2] = o; t[o].fa = pa;
connect(o, fa, d1 ^ 1), connect(fa, b, d1);
pushup(fa), pushup(o);
}
inline void splay(int o) {
int x = o, tp = 0;
st[++tp] = x;
while (!isroot(x)) st[++tp] = x = t[x].fa;
while (tp) pushdown(st[tp--]);
while (!isroot(o)) {
int fa = t[o].fa;
if (isroot(fa)) rotate(o);
else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
else rotate(o), rotate(o);
}
}
inline void access(int o) {
for (int x = 0; o; o = t[x = o].fa)
splay(o), t[o].rc = x, pushup(o);
}
inline void mkrt(int o) {
access(o), splay(o);
t[o].rev ^= 1, std::swap(t[o].lc, t[o].rc), std::swap(t[o].ls, t[o].rs);
}
inline int getrt(int o) {
access(o), splay(o);
while (pushdown(o), t[o].lc) o = t[o].lc;
return splay(o), o;
}
inline void link(int x, int y) {
mkrt(x);
if (getrt(y) != x) t[x].fa = y;
}
inline void cut(int x, int y) {
mkrt(x), access(y), splay(y);
if (t[y].lc == x && !t[x].rc) t[y].lc = t[x].fa = 0, pushup(y);
} inline void work() {
while (m--) {
int opt, x, y, d;
read(opt), read(x), read(y);
if (opt == 1) cut(x, y);
else if (opt == 2) link(x, y);
else if (opt == 3) read(d), getrt(x) == getrt(y) && (mkrt(x), access(y), splay(y), t[y] = add_tag(t[y], d), 1);
else if (getrt(x) != getrt(y)) puts("-1");
else {
mkrt(x), access(y), splay(y);
ll sum = t[y].sum, cnt = (ll)t[y].sz * (t[y].sz + 1) / 2, p = std::__gcd(sum, cnt);
printf("%lld/%lld\n", sum / p, cnt / p);
}
}
} inline void init() {
read(n), read(m);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= n; ++i) t[i].v = a[i], pushup(i);
int x, y;
for (int i = 1; i < n; ++i) read(x), read(y), link(x, y);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

bzoj3091 城市旅行 LCT + 区间合并的更多相关文章

  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区间合并 前三个 ...

  2. 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& ...

  3. BZOJ3091 城市旅行 LCT

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

  4. 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 ...

  5. 【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 ...

  6. 【LCT】BZOJ3091 城市旅行

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

  7. bzoj 3091: 城市旅行 LCT

    题目: http://www.lydsy.com/JudgeOnline/problem.php?id=3091 题解: 首先前三个操作就是裸的LCT模板 只考虑第四个操作. 要求我们计算期望,所以我 ...

  8. BZOJ 3091: 城市旅行 [LCT splay 期望]

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

  9. BZOJ 3091: 城市旅行 lct 期望 splay

    https://www.lydsy.com/JudgeOnline/problem.php?id=3091 https://blog.csdn.net/popoqqq/article/details/ ...

随机推荐

  1. EDM数据:如何选择邮件服务器平台

    博主知道有不少的企业和个人都在寻找邮件服务器平台,下面博主从下面几个方面给大家介绍一下如何选择. 一.列表管理功能是否完善. 一般一个好的邮件服务器平台系统都有完善的列表管理功能.列表管理功能是指邮件 ...

  2. EDM邮件营销真的落伍了吗?

    很多朋友都觉得EDM邮件营销已经日暮西山了.难道EDM邮件营销真的落伍过时了吗?小编本文为大家讲解一下. 一.有数据为证:目前电子邮件仍然比较活跃,九成以上的用户每天至少查看一封邮件,并且6成以上的人 ...

  3. python中单下划线和双下划线的区别

    1.python中双下划线(__str__)代表这个变量是特殊变量,是可以直接访问的 __xxx___ 定义的是特列方法.像__init__之类的 2.python前面双划线(__name)代表这个变 ...

  4. vs2010 setup 打包 安装 BAT批处理实现自动安装软件功能

    CLS@echo offECHO.ECHO 安装 Diskeeper 7.0.428ECHO 请稍等...start /wait %systemdrive%\install\Applications\ ...

  5. spring几种获取 HttpServletRequest 对象的方式

    以下的 request 实例都编号了,一共 4 种 方式 1.@Autowired 方式2.public void Test(HttpServletRequest request1, HttpServ ...

  6. CSS3——背景 文本 字体 链接 列表样式 表格

    背景 background-color rgb(255,0,0,1)      最后一个值表示透明度,范围是 0--1 background-image 默认平铺重复显示 background-rep ...

  7. poker

    一副扑克牌有n张牌.一般你买的一副新扑克牌里除了这n张牌外还会有一些张特殊的牌,如果你不小心弄丢了n张牌中的某一张,就可以用特殊牌来代替,但是如果你弄丢两张的话就没有办法了,因为特殊牌上的图案是一样的 ...

  8. 【Linux开发】OpenCV在ARM上的移植

    与X86 Linux类似,请参考:Linux 下编译安装OpenCV 本文在此基础上进行进一步操作. 网络上很多移植编译的方法比较老,多数针对OpenCV 1.0,而且方法很麻烦,不仔细操作很容易出错 ...

  9. 【Linux开发】Linux启动脚本设置

    前言linux有自己一套完整的启动 体系,抓住了linux启动 的脉络,linux的启动 过程将不再神秘.阅读之前建议先看一下附图.本文中假设inittab中设置的init tree为:/etc/rc ...

  10. vue+sentry 前端异常日志监控

    敲代码最糟心不过遇到自己和测试的环境都OK, 客户使用有各种各样还复现不了的问题,被逼无奈只能走到这一步:前端异常日志监控! vue官方文档如下推荐: 就是说, vue有错误机制处理errorHand ...