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. jquery 手机 图片切换 例子 网址

    http://m.swdhy.com/page/ShowCompany.aspx?cid=388481&name=山东潍坊金城服装有限公司

  2. UIButton图文上下对齐

    - (void)centerImageAndTitle:(float)spacing { // get the size of the elements here for readability CG ...

  3. 使用jsdoc-toolkit来自动生成js api文档

    近来前端组小盆友开发的类库越来越多,很多情况下彼此不知道写了些什么方法,为了更好的合作提高工作效率,找了个比较好的api文档生成方法.使用jsdoc-toolkit来自动生成js api文档. 一.  ...

  4. Swift学习笔记八:枚举

    1. 枚举语法      1)枚举的定义 使用enum关键词而且把它们的整个定义放在一对大括号内: enum SomeEumeration { // enumeration definition go ...

  5. SSL 错误

    javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?    at com.sun.net.ssl.in ...

  6. 『零行代码』解决键盘遮挡问题(iOS)

    关注仓库,及时获得更新:iOS-Source-Code-Analyze https://github.com/draveness/iOS-Source-Code-Analyze Follow: Dra ...

  7. Microsoft Windows Server 2008 R2 IIS7.5安装指南

    一.IIS安装步骤: 1.安装Windows Server 2008 R2(见 附录一) 2.配置计算机名称和IP地址(见 附录一) 3.配置成员服务器(见 附录一) 4.点击任务栏上的“服务器管理器 ...

  8. oracle周数计算方法

    从星期天开始起算 Function Fn_GetWeekbyDate(P_Date Varchar2) Return Varchar2 Is Begin Return To_char(To_Date( ...

  9. 常用的 css 命名规则

    头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...

  10. 绝对炫的幻灯片插件-SKITTER

    绝对炫的幻灯片插件-SKITTER 所属分类:媒体-幻灯片和轮播图,图片展示,滑块和旋转 Includes code source // Styles <link href="css/ ...