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. C# SQL多条件查询拼接技巧

    本文转载:http://blog.csdn.net/limlimlim/article/details/8638080 #region 多条件搜索时,使用List集合来拼接条件(拼接Sql) Stri ...

  2. VMware-workstation-full-12.0.1-3160714

    https://download3.vmware.com/software/wkst/file/VMware-workstation-full-12.0.1-3160714.exe 5A02H-AU2 ...

  3. Boost.Asio c++ 网络编程翻译(20)

    异步服务端 这个图表是相当复杂的:从Boost.Asio出来你能够看到4个箭头指向on_accept.on_read,on_write和on_check_ping. 着也就意味着你永远不知道哪个异步调 ...

  4. 往另外1个ListView中添加当前选中的项目

      //往另外1个ListView中添加当前选中的项目   function AddSelItems(listview1:TListView;ListView2:TListView):Boolean; ...

  5. Linux Increase The Maximum Number Of Open Files / File Descriptors (FD)

    How do I increase the maximum number of open files under CentOS Linux? How do I open more file descr ...

  6. 10.13 noip模拟试题

    Porble 1时间与空间之旅(tstrip.*) 题目描述 公元22××年,宇宙中最普遍的交通工具是spaceship.spaceship的出现使得星系之间的联系变得更为紧密,所以spaceship ...

  7. 23、Javascript DOM

    DOM Document Object Model(文档对象模型)定义了html和xml的文档标准. DOM 节点树 <html> <head> <title>DO ...

  8. $(this).next()与$(this).children()

    $(this).next() 当前元素同级的下个元素,而非子元素 $(this).children() 是当前元素的下一级元素的集合,就是子元素的集合,而不管子元素的后代元素 所以这两个没有什么可比性 ...

  9. JQ 日期格式化

    将字符转换为日期格式: function getDate(strDate) { var date = eval('new Date(' + strDate.replace(/\d+(?=-[^-]+$ ...

  10. aliyun云服务器硬件性能测试

    1.所购买阿里云服务器信息 2.dd命令测试 3.