bzoj 3091: 城市旅行 LCT
题目:
题解:
首先前三个操作就是裸的LCT模板
只考虑第四个操作.
要求我们计算期望,所以我们考虑计算出所有情况的和然后在除以情况的数目.
这样我们就找到分子分母了.
我们很容易发现分母即为\(\frac{n*(n+1)}{2}\)
对应到我们的Splay树上即\(\frac{siz*(siz+1)}{2}\)
所以我们现在考虑维护分子:
对于首先我们考虑在一个长为n的序列上统计这些东西
我们知道总和即为每一项乘以这一项出现的次数(又在废话)
出现的次数又是多少呢?
a_1 & a_2 & a_3 & ... & a_i &... & a_n \\
1*n & 2*(n-1) & 3*(n-2) & ...&i*(n-i+1) & ...& n*1 \\
\end{matrix}
\]
所以其实对于每一个元素,出现的次数都是\((\text{左边的}siz+1)*(\text{右边的}siz+1)\)
那么我们考虑合并:
假设这个区间作为合并的左区间,我们设\(w = \text{右区间的}siz+1\)(即这个区间合并后右侧新出现的节点数)
那么按照刚才的思路,所有的数字的后一项都会同时增大即变为:
a_1 & a_2 & a_3 & ... & a_i &... & a_n \\
1*(n+w) & 2*(n-1+w) & 3*(n-2+w) & ...&i*(n-i+1+w) & ...& n*(1+w) \\
\end{matrix}
\]
于是我们发现实际上这段区间的贡献增加了:
a_1 & a_2 & a_3 & ... & a_i &... & a_n \\
1*w & 2*w & 3*w & ...& i*w & ...& n*w \\
\end{matrix}
\]
所以我们记录一个和表示\(1*a_1 + 2*a_2 + 3*a_3 + ... + n*a_n\)即可
利用这个我们就可以维护分子了。啥?? 怎么维护 ??
\(val = ch[0]->val + ch[1]->val + ch[0]->lsum*(ch[1]->siz + 1) + ch[1]->rsum*(ch[0]->siz + 1) + w*(ch[0]->siz + 1)*(ch[1]->siz + 1);\)
其中\(w\)为节点本身的权,\(lsum = \sum_{i=1}^{n}a_i*i\),\(rsum = \sum_{i=1}^{n}a_i*(n-i+1)\)
至于维护\(lsum\)和\(rsum\)的过程.
我们有
\]
据说是小学数学难度.
夭折啊 !我想不出来 !
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ll;
inline void read(ll &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const ll maxn = 50010;
struct Node{
Node *ch[2],*fa;
ll w,lsum,rsum,lazy;
ll val,siz,tag,sum;
void update();
void pushdown();
void rev();
void inc(ll x);
}*null;
void Node::rev(){
if(this == null) return;
swap(lsum,rsum);swap(ch[0],ch[1]);
tag ^= 1;
}
void Node::inc(ll x){
if(this == null) return;
w += x;sum += x*siz;
lsum += x*siz*(siz+1)/2;
rsum += x*siz*(siz+1)/2;
val += x*siz*(siz+1)*(siz+2)/6;
lazy += x;
}
void Node::pushdown(){
if(this == null) return;
if(lazy){
if(ch[0] != null) ch[0]->inc(lazy);
if(ch[1] != null) ch[1]->inc(lazy);
lazy = 0;
}
if(tag){
if(ch[0] != null) ch[0]->rev();
if(ch[1] != null) ch[1]->rev();
tag = 0;
}
}
void Node::update(){
if(this == null) return;
siz = ch[0]->siz + ch[1]->siz + 1;
sum = ch[0]->sum + ch[1]->sum + w;
lsum = ch[0]->lsum + w*(ch[0]->siz + 1) + ch[1]->lsum + ch[1]->sum*(ch[0]->siz + 1);
rsum = ch[1]->rsum + w*(ch[1]->siz + 1) + ch[0]->rsum + ch[0]->sum*(ch[1]->siz + 1);
val = ch[0]->val + ch[1]->val + ch[0]->lsum*(ch[1]->siz + 1) + ch[1]->rsum*(ch[0]->siz + 1) + w*(ch[0]->siz + 1)*(ch[1]->siz + 1);
}
Node mem[maxn],*it;
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null->fa = null;
null->w = null->lsum = null->rsum = null->sum =
null->val = null->siz = null->tag = 0;
}
inline Node* newNode(ll x){
Node *p = it++;p->ch[0] = p->ch[1] = p->fa = null;
p->w = p->val = p->lsum = p->rsum = p->sum = x;p->siz = 1;
p->tag = p->lazy = 0;
return p;
}
inline void rotate(Node *p,Node *x){
ll k = p == x->ch[1];
Node *y = p->ch[k^1],*z = x->fa;
if(z->ch[0] == x) z->ch[0] = p;
if(z->ch[1] == x) z->ch[1] = p;
if(y != null) y->fa = x;
p->fa = z;p->ch[k^1] = x;
x->fa = p;x->ch[k] = y;
x->update();p->update();
}
inline bool isRoot(Node *p){
return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p);
}
inline void Splay(Node *p){
p->pushdown();
while(!isRoot(p)){
Node *x = p->fa,*y = x->fa;
y->pushdown();x->pushdown();p->pushdown();
if(isRoot(x)) rotate(p,x);
else if((p == x->ch[0])^(x == y->ch[0])) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}p->update();
}
inline Node* Access(Node *x){
for(Node *y = null;x != null;y = x,x = x->fa)
Splay(x),x->ch[1] = y,x->update();
return x;
}
inline void makeRoot(Node *x){
Access(x);Splay(x);x->rev();
}
inline void link(Node *x,Node *y){
makeRoot(x);x->fa = y;
}
inline void cut(Node *x,Node *y){
makeRoot(x);Access(y);Splay(y);
if(y->ch[0] == x && x->ch[1] == null){
y->ch[0] = y->ch[0]->fa = null;
y->update();
}
}
inline void inc(Node *x,Node *y,ll w){
makeRoot(x);Access(y);Splay(y);
y->inc(w);
}
inline ll gcd(const ll &a,const ll &b){return b == 0 ? a : gcd(b,a%b);}
inline ll query(Node *x,Node *y){
makeRoot(x);Access(y);Splay(y);
ll upside = y->val;
ll dnside = y->siz*(y->siz + 1)/2;
ll g = gcd(upside,dnside);
printf("%llu/%llu\n",upside/g,dnside/g);
}
inline Node* findRoot(Node *x){
Access(x);Splay(x);
while(x->ch[0] != null) x = x->ch[0];
Splay(x);return x;
}
int main(){
init();
ll n,m;read(n);read(m);
for(ll i=1,x;i<=n;++i){
read(x);newNode(x);
}
ll u,v;
for(ll i=1;i<n;++i){
read(u);read(v);
link(mem+u,mem+v);
}
ll op;
while(m--){
read(op);
if(op == 1){
read(u);read(v);
if(u != v && findRoot(mem+u) == findRoot(mem+v)) cut(mem+u,mem+v);
}else if(op == 2){
read(u);read(v);
if(findRoot(mem+u) != findRoot(mem+v)) link(mem+u,mem+v);
}else if(op == 3){
read(u);read(v);read(op);
if(findRoot(mem+u) == findRoot(mem+v)) inc(mem+u,mem+v,op);
}else if(op == 4){
read(u);read(v);
if(findRoot(mem+u) == findRoot(mem+v)) query(mem+u,mem+v);
else puts("-1");
}
}
getchar();getchar();
return 0;
}
bzoj 3091: 城市旅行 LCT的更多相关文章
- BZOJ 3091: 城市旅行 [LCT splay 期望]
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1454 Solved: 483[Submit][Status][Discuss ...
- BZOJ 3091: 城市旅行 lct 期望 splay
https://www.lydsy.com/JudgeOnline/problem.php?id=3091 https://blog.csdn.net/popoqqq/article/details/ ...
- bzoj 3091 城市旅行(LCT+数学分析)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3091 [思路] 膜Popoqqq大爷的题解 click here [代码]是坑... ...
- BZOJ 3091 城市旅行
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
[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 ...
- 【BZOJ】3091: 城市旅行 Link-Cut Tree
[题意]参考PoPoQQQ. 给定一棵树,每个点有一个点权,提供四种操作: 1.删除两点之间的连边 不存在边则无视 2.在两点之前连接一条边 两点已经联通则无视 3.在两点之间的路径上所有点的点权加上 ...
- bzoj3091 城市旅行 LCT + 区间合并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3091 题解 调了整个晚自习才调出来的问题. 乍一看是个 LCT 板子题. 再看一眼还是个 LC ...
- 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区间合并 前三个 ...
随机推荐
- recognition rate generalization识别率 泛化
http://www1.inf.tu-dresden.de/~ds24/lehre/ml_ws_2013/ml_11_hinge.pdf Two extremes: • Big
- Python菜鸟之路:Python基础-类(1)——概念
什么是类? 在python中,把具有相同属性和方法的对象归为一个类(class).类是对象的模板或蓝图,类是对象的抽象化,对象是类的实例化.类不代表具体的事物,而对象表示具体的事物. 类的创建 cla ...
- 【译】用 Chart.js 做漂亮的响应式表单
数据包围着我们.虽然搜索引擎和其他应用都对基于文本方式表示的数据偏爱有加,但人们发现可视化是更容易理解的一种方式.今年初,SitePoint 发表了 Aurelio 的文章< Chart.js简 ...
- Android Message handling (based on KK4.4)
一.几个关键概念 1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列.存放消息的地方.每个线程最多仅仅能够拥有一个MessageQueue数据结构. 创建一个线程的时候,并不会自 ...
- ABAP 面向对象(Object Orientation) OO
[转自 http://blog.sina.com.cn/s/blog_7c7b16000101bhof.html]在程序中, 对象的识别和寻址是通过对象引用来实现的, 对象引用变量可以访问对象的属性和 ...
- ceph基本架构简述
1. 介绍 云硬盘是IaaS云平台的重要组成部分,云硬盘给虚拟机提供了持久的块存储设备.目前的AWS 的EBS(Elastic Block store)给Amazon的EC2实例提供了高可用高可靠的块 ...
- Linux系统BTC挖矿傻瓜教程
[Linux系统BTC/比特币矿池挖矿方案一]cgminer矿池挖矿程序(Linux系统 比特币(BTC) 矿池挖矿/采矿/造币)cgminer矿池挖矿程序[查看这里有没有最新版]http://ck. ...
- python基础16 ----面向对象程序设计二
一.继承与派生 1.继承的定义:继承是一种创建新类的方式,即在类中提取共同的部分创建出一个类,这样的类称为父类,也可称为基类和超类,新建的类称为派生类或子类. 2.单继承:就相当于子类继承了一个父类. ...
- QCon2016 上海会议汇总(2) - 团队管理
QCon 2016上海日程:http://2016.qconshanghai.com/schedule <当你的团队还支撑不起梦想时> - 链尚网技术合伙人 杨荣伟 Figo讲述了如何训练 ...
- iOS 在视图控制器里面判断 应用程序的前台 后台切换 UIViewController
1.时机 用户点击home 键 应用退到后台 再次点击进入前台 在UIViewController里面 控制器如何获取相关的事件? 2.需求 (1)NSTimer 在应用程序进入后台 10秒 ...