BZOJ 3091 城市旅行
Description
.jpg)
Input
.jpg)
Output
.jpg)
Sample Input
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 Output
6/1
HINT
对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N
Source
维护方法我就不再赘述了,见我博客的 BZOJ 2572 高速公路。这一题和那一题的维护方法其实是一样的,但是数据结构不同,很明显这是lct嘛。
但是那么问题就来,树上的序号id不是一定的,不像线段树一样,怎么办呢???
这就是本题的难点——维护id。但是细细想想其实也不是很难。
你想,他是要维护一条链上深度的id,左子树id<右子树,其实我们就是在access操作中对某一条链的id整体加上一个值或者减去一个值,这样来操作(splay维护的都是一条链)。因此,维护id就不成问题。
但是你有没有考虑过这样一种情况:根翻转了,他所在splay的id也全部都要翻转,这怎么办?其实也不难,将其所在splay中所有id都取负,再加上splay的size+1即可。
代码实现有许多的细节要处理:比如初始化连边,他貌似卡了你的link,如果你直接连的话,正确的做法是dfs直接将father连上去(这就是我开始tle了八九发的原因)。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std; typedef long long ll;
#define maxn 50010
int n,m,ch[maxn][],size[maxn],fa[maxn],stack[maxn];
int side[maxn],next[maxn*],toit[maxn*],cnt;
ll key[maxn],id[maxn],s1[maxn],s2[maxn],s3[maxn];
ll lef[maxn],rig[maxn],sign1[maxn],sign2[maxn];
bool rev[maxn]; inline int getint()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} inline ll getlong()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} inline ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } inline void pushdown(int x)
{
int lc = ch[x][],rc = ch[x][];
if (rev[x])
{
id[x] = -id[x]; s2[x] = -s2[x];
swap(lef[x],rig[x]);
lef[x] = -lef[x]; rig[x] = -rig[x];
swap(ch[x][],ch[x][]);
if (lc) rev[lc] ^= ,sign2[lc] = -sign2[lc];
if (rc) rev[rc] ^= ,sign2[rc] = -sign2[rc];
rev[x] = false;
}
if (sign2[x])
{
lef[x] += sign2[x]; rig[x] += sign2[x]; id[x] += sign2[x];
s3[x] += (sign2[x]*s2[x]<<)+sign2[x]*sign2[x]*s1[x];
s2[x] += sign2[x]*s1[x];
if (lc) sign2[lc] += sign2[x];
if (rc) sign2[rc] += sign2[x];
sign2[x] = ;
}
if (sign1[x])
{
s1[x] += sign1[x]*(ll)size[x];
s2[x] += (ll)size[x]*(lef[x]+rig[x])/*sign1[x];
s3[x] += (rig[x]*(rig[x]+)*((rig[x]<<)+)/-(lef[x]-)*lef[x]*((lef[x]<<)-)/)*sign1[x];
key[x] += sign1[x];
if (lc) sign1[lc] += sign1[x];
if (rc) sign1[rc] += sign1[x];
sign1[x] = ;
}
} inline void updata(int x)
{
int lc = ch[x][],rc = ch[x][];
if (lc) pushdown(lc); if (rc) pushdown(rc);
size[x] = size[lc]+size[rc]+;
s1[x] = s1[lc]+s1[rc]+key[x];
s2[x] = id[x]*key[x]+s2[lc]+s2[rc];
s3[x] = id[x]*id[x]*key[x]+s3[lc]+s3[rc];
lef[x] = rig[x] = id[x];
if (lc) lef[x] = lef[lc];
if (rc) rig[x] = rig[rc];
} inline bool isroot(int a) { return ch[fa[a]][] != a&&ch[fa[a]][] != a; } inline void rotate(int x)
{
int y = fa[x],z = fa[y],l = ch[y][]==x,r = l^;
if (!isroot(y)) ch[z][ch[z][]==y] = x; fa[x] = z;
if (ch[x][r]) fa[ch[x][r]] = y; ch[y][l] = ch[x][r];
ch[x][r] = y; fa[y] = x;
updata(y); updata(x);
} inline void splay(int x)
{
int top = ,i;
for (i = x;!isroot(i);i = fa[i]) stack[++top] = i;
stack[++top] = i;
while (top) pushdown(stack[top--]);
while (!isroot(x))
{
int y = fa[x],z = fa[y];
if (!isroot(y))
{
if ((ch[y][]==x)^(ch[z][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
} inline int access(int x)
{
int t;
for (t = ;x;t = x,x = fa[x])
{
splay(x);
if (ch[x][]) sign2[ch[x][]] -= size[ch[x][]]+;
ch[x][] = t;
if (t) sign2[t] += size[ch[x][]]+;
updata(x);
}
return t;
} inline void evert(int x)
{
x = access(x); rev[x] ^= ;
sign2[x] += rev[x]*(size[x]+);
} inline int find(int x)
{
x = access(x);
while (pushdown(x),ch[x][]) x = ch[x][];
return x;
} inline void cut(int x,int y)
{
evert(x); access(y); splay(y);
if (ch[y][] != x||ch[x][] != ) return;
ch[y][] = fa[x] = ;
updata(x);
sign2[y] -= size[x];
} inline void link(int x,int y)
{
if (find(x) == find(y)) return;
evert(x); fa[x] = y;
} inline void change(int x,int y,ll v)
{
if (find(x) != find(y)) return;
evert(x); x = access(y);
sign1[x] += v;
pushdown(x);
} inline void ask(int x,int y)
{
if (find(x) != find(y)) { printf("-1\n"); return; }
evert(x); access(y); splay(x);
ll up = -s3[x]+(ll)(size[x]+)*s2[x],down = (ll)size[x]*(ll)(size[x]+)>>,d = gcd(up,down);
up /= d; down /= d;
printf("%lld/%lld\n",up,down);
} inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; } inline void ins(int a,int b) { add(a,b); add(b,a); } inline void dfs(int now,int f)
{
if (f) fa[now] = f;
for (int i = side[now];i;i = next[i])
if (toit[i] != f) dfs(toit[i],now);
} int main()
{
freopen("3091.in","r",stdin);
freopen("3091.out","w",stdout);
scanf("%d %d",&n,&m);
for (int i = ;i <= n;++i)
{
key[i] = getlong();
s1[i] = s2[i] = s3[i] = key[i];
size[i] = lef[i] = rig[i] = id[i] = ;
}
for (int i = ;i < n;++i)
{
int a = getint(),b = getint();
ins(a,b);
}
dfs(,);
while (m--)
{
int opt = getint();
if (opt == )
{
int u = getint(),v = getint(); ll d = getlong();
change(u,v,d);
}
else
{
int u = getint(),v = getint();
if (opt == ) cut(u,v);
else if (opt == ) link(u,v);
else ask(u,v);
}
}
fclose(stdin); fclose(stdout);
return ;
}
BZOJ 3091 城市旅行的更多相关文章
- BZOJ 3091: 城市旅行 [LCT splay 期望]
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1454 Solved: 483[Submit][Status][Discuss ...
- bzoj 3091 城市旅行(LCT+数学分析)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3091 [思路] 膜Popoqqq大爷的题解 click here [代码]是坑... ...
- 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 题解: 首先前三个操作就是裸的LCT模板 只考虑第四个操作. 要求我们计算期望,所以我 ...
- 【BZOJ】3091: 城市旅行 Link-Cut Tree
[题意]参考PoPoQQQ. 给定一棵树,每个点有一个点权,提供四种操作: 1.删除两点之间的连边 不存在边则无视 2.在两点之前连接一条边 两点已经联通则无视 3.在两点之间的路径上所有点的点权加上 ...
- 【LCT】BZOJ3091 城市旅行
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1927 Solved: 631[Submit][Status][Discuss ...
- luogu P4842 城市旅行
嘟嘟嘟 好题,好题 刚开始突发奇想写了一个\(O(n ^ 2)\)暴力,结果竟然过了?!后来才知道是上传题的人把单个数据点开成了10s-- 不过不得不说我这暴力写的挺好看的.删边模仿链表删边,加边的时 ...
- 【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 ...
- (RERERERERERERERERERERE) BZOJ 2746: [HEOI2012]旅行问题
二次联通门 : BZOJ 2746: [HEOI2012]旅行问题 神TM STL的vector push_back进一个数后取出时就变成了一个很小的负数.. 调不出来了, 不调了 #include ...
随机推荐
- Hadoop最基本的wordcount(统计词频)
package com.uniclick.dapa.dstest; import java.io.IOException; import java.net.URI; import org.apache ...
- 树莓派安装mjpg-streamer视频监控 分类: Raspberry Pi 2015-04-12 23:41 144人阅读 评论(0) 收藏
原来使用Motion在树莓派上跑1280x720分辨率的三颗摄像头.占用内存太严重,关闭诸多功能之后还是不行.故转战mjpg-streamer. 首先安装所需软件 sudo apt-get insta ...
- Android中关于在onDrow或者onMeasure中创建对象提示Avoid object allocations during draw/layout operations (preallocate and reuse instead) 问题
在实际开发中Android中自带的控件有时无法满足我们的需求,这时就需要我们重写控件来实现我们想要的功能. 还有个关于UI体验的问题,就是在onDraw()函数中最好不要去创建对象,否则就提示下面的警 ...
- Windows7如何在安全模式下卸载驱动(亲测)
在桌面“我的电脑”上点鼠标右键,选择“属性”,“硬件”,“设备管理器”,找到“显示卡选项”,打开前面的“+”,然后按鼠标右键,选择“卸载”就可以了. (亲测,主板驱动卸载成功启动)
- 走进 Facebook POP 的世界
POP: 一个流行的可扩展的动画引擎iOS,它支持spring和衰变动态动画,使其可用于构建现实,基于物理交互.Objective - C API允许快速集成, 对于所有的动画和过渡他是成熟的. 解释 ...
- FastDFS问题汇总
问题1: 增加分组后,新的storge不可用. 增加一个分组group2,发现上传文件失败.在group2中的storage中使用netstat -anp|grep fdfs,发现端口状态为CLOSE ...
- java中调用js脚本
JDK1.6加入了对Script(JSR223)的支持.这是一个脚本框架,提供了让脚本语言来访问Java内部的方法.你可以在运行的时候找到脚本引擎,然后调用这个引擎去执行脚本.这个脚本API允许你为脚 ...
- Java基础知识强化之集合框架笔记17:List集合的特有的遍历功能
1. List集合的特有遍历功能: size()和 get()方法结合使用 2. 代码示例: package cn.itcast_03; import java.util.ArrayList; imp ...
- LINUX启动顺序
Linux 启动顺序: 1. BIOS自检 (服务器硬件启动的第一步,坑定的啦) 2. 运行系统内核并检测硬件(这个是看系统了,redhat等相关版本是通过/boot/vm进行启动 vmlinuz) ...
- vim字符串替换
vi/vim 中可以使用 :s 命令来替换字符串.以前只会使用一种格式来全文替换,今天发现该命令有很多种写法(vi 真是强大啊,还有很多需要学习),记录几种在此,方便以后查询. :s/vivian/s ...