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 Output

16/3
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 城市旅行的更多相关文章

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

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

  2. bzoj 3091 城市旅行(LCT+数学分析)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3091 [思路] 膜Popoqqq大爷的题解 click here [代码]是坑... ...

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

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

  4. bzoj 3091: 城市旅行 LCT

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

  5. 【BZOJ】3091: 城市旅行 Link-Cut Tree

    [题意]参考PoPoQQQ. 给定一棵树,每个点有一个点权,提供四种操作: 1.删除两点之间的连边 不存在边则无视 2.在两点之前连接一条边 两点已经联通则无视 3.在两点之间的路径上所有点的点权加上 ...

  6. 【LCT】BZOJ3091 城市旅行

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

  7. luogu P4842 城市旅行

    嘟嘟嘟 好题,好题 刚开始突发奇想写了一个\(O(n ^ 2)\)暴力,结果竟然过了?!后来才知道是上传题的人把单个数据点开成了10s-- 不过不得不说我这暴力写的挺好看的.删边模仿链表删边,加边的时 ...

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

  9. (RERERERERERERERERERERE) BZOJ 2746: [HEOI2012]旅行问题

    二次联通门 : BZOJ 2746: [HEOI2012]旅行问题 神TM STL的vector push_back进一个数后取出时就变成了一个很小的负数.. 调不出来了, 不调了 #include ...

随机推荐

  1. Python基础知识---字典

    现在在实习期间,好久没用Python了,今天在做Java项目时用的HashMap让我联想到了Python中的字典,就写一些Python字典的知识吧,复习复习. 字典:  key --> valu ...

  2. win7重装系统时,使用PE工具箱进入系统看到的“C盘变成0.2G,D盘变成48G左右”这是什么回事?

    引入: 今天帮同学重装系统,重装系统使用的方法是利用PE工具箱制作出启动U盘,进行重装系统. 我的步骤是 第一步:开机按F2挂载U盘优先启动,于是开机时就进入PE微系统 第二步: 用分区工具(Disk ...

  3. PIC16F877A最小功能板 - 原理图系列

    一.顶层 主要由port转换.MCU.复位.键盘.晶振和显示等5部分电路组成. 二.模块层 1. port转换电路 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...

  4. Apache + Tomcat集群配置详解 (1)

    一.软件准备 Apache 2.2 : http://httpd.apache.org/download.cgi,下载msi安装程序,选择no ssl版本 Tomcat 6.0 : http://to ...

  5. js控件位置

    function ShowSettingDiv() { var div = document.getElementById('ShowDiv'); //将要弹出的层 div.style.display ...

  6. hdu 3450 Counting Sequences

    /* n*n暴力 这个很好想 */ #include<cstdio> #define maxn 100010 #define mod 9901 using namespace std; i ...

  7. JAVA 安装与配置

    JDK是整个java的核心,包括java的运行环境.java工具和java基础类库. 一.安装JDK 获得JDK,登录oracle网站http://www.oracle.com/technetwork ...

  8. SQL:42601

    以前遇到SQL中触发器的问题, 添加一个字段后,发现以前的程序的SQL报错 看了下表定义,有这样的一行代码 CREATE TRIGGER chintai_keiyaku_audit AFTER INS ...

  9. MongoDB_1

    突然想去看下MongoDB的东西,于是有了这篇文章.其实很早以前就看过一些关于NoSql的文章,还记得当时里面有介绍MongoDB的,多瞅了2眼,并且在Window下安装了MongoDB的驱动,小玩了 ...

  10. VMware复制Centos6虚拟机要改的地方

    1.删除文件 /etc/udev/rules.d/70-persistent-net.rules  (它会绑定你网卡信息) 2.重新配置 # vi /etc/sysconfig/network-scr ...