P4842 城市旅行
题目链接
题意分析
首先存在树上的删边连边操作 所以我们使用\(LCT\)维护
然后考虑怎么维护答案
可以发现 对于一条链 我们编号为\(1,2,3,...,n\)
那么期望就是
\]
很显然的 对于当前点\(i\)
穿过\(i\)的区间的左端点有\(i\)个
右端点有\(n-i+1\)个
乘法原理组合一下就可以了
总共的路径就存在\(\frac{n*(n+1)}{2}\)条
分母我们在最后询问的时候直接用求就可以了
关键是我们怎么在\(LCT\)上维护分子
首先对于当前的\(LCT\)
我们考虑一下对于一种情况
a1---a2---a3---a4(根节点)---a5----a6----a7
左边一开始的答案是\(a_1*1*3+a_2*2*2+a_3*3*1\)
然后加入这一条链之后就是\(a_1*1*7+a_2*2*6+a_3*3*5\)
做差之后就是 \(a_1*1*4+a_2*2*4+a_3*3*4\)
也就是\((a_1*1+a_2*2+a_3*3)*(siz_{rc}+1)\)
所以我们维护一个
\]
那么左边增加的值就是\(lsum_{lc}*(siz_{rc}+1)\)
同理对于右边我们维护
\]
那么右边增加的值就是\(rsum_{rc}*(siz_{lc}+1)\)
那么
\]
然后我们同样需要维护\(lsum\)以及\(rsum\)
\]
\]
仔细想一下 式子应该很好理解的
这样的话我们就可以应对\(query()\)的部分了
然后我们需要维护修改的部分
首先 我们思考一下一条链加一个值的影响
首先 单点值以及当前链总和比较好维护
\(lsum\)以及\(rsum\)也就是\(+d*\frac{n* (n+1)}{2}\)
关键是怎么维护分子\(val\)呢
\]
然后再捯饬一下
\]
\]
\]
\]
这样的话我们就可以很好地维护了
同时又要输出最简分数 所以需要求\(gcd\)
CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 308611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
T __=0,___=1;char ____=getchar();
while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
_=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
struct LCT
{
int fa,son[2];
ll sum,lsum,rsum,val,num,down_tag,siz;
//子树大小其实不用开 long long
//但是由于我自己手写代码的原因 不开long long会WA两个点
bool tag;
}tre[M];
int n,m,tot,top;
int sta[M];
IL ll gcd(ll x,ll y){return y ? gcd(y,x%y):x;}
IL bool isroot(int x){return !((tre[tre[x].fa].son[0]==x)||(tre[tre[x].fa].son[1]==x));}
IL void pushup(int x)
{
tre[x].sum=tre[tre[x].son[0]].sum+tre[tre[x].son[1]].sum+tre[x].num;
tre[x].siz=tre[tre[x].son[0]].siz+tre[tre[x].son[1]].siz+1;
tre[x].val=tre[tre[x].son[0]].val+tre[tre[x].son[1]].val+tre[tre[x].son[0]].lsum*(tre[tre[x].son[1]].siz+1)+tre[tre[x].son[1]].rsum*(tre[tre[x].son[0]].siz+1)+tre[x].num*(tre[tre[x].son[0]].siz+1)*(tre[tre[x].son[1]].siz+1);
tre[x].lsum=tre[tre[x].son[0]].lsum+tre[tre[x].son[1]].lsum+tre[tre[x].son[1]].sum*(tre[tre[x].son[0]].siz+1)+tre[x].num*(tre[tre[x].son[0]].siz+1);
tre[x].rsum=tre[tre[x].son[0]].rsum+tre[tre[x].son[1]].rsum+tre[tre[x].son[0]].sum*(tre[tre[x].son[1]].siz+1)+tre[x].num*(tre[tre[x].son[1]].siz+1);
}
IL void chenge(int y,ll d)
{
ll cdy=((tre[y].siz+1)*tre[y].siz/2),wzy=(tre[y].siz-1)*tre[y].siz*(tre[y].siz*2-1)/6;
tre[y].sum+=tre[y].siz*d;
tre[y].num+=d;
tre[y].lsum+=cdy*d;
tre[y].rsum+=cdy*d;
tre[y].val+=((cdy*tre[y].siz)-(wzy+tre[y].siz*(tre[y].siz-1)/2))*d;
tre[y].down_tag+=d;
}
IL void rever(int x)
{
swap(tre[x].son[0],tre[x].son[1]);
//交换子树的话 lsum以及$rsum$也会发生改变
swap(tre[x].lsum,tre[x].rsum);
tre[x].tag^=1;
}
IL void down(int x)
{
if(tre[x].tag)
{
if(tre[x].son[0]) rever(tre[x].son[0]);
if(tre[x].son[1]) rever(tre[x].son[1]);
tre[x].tag^=1;
}
if(tre[x].down_tag)
{
chenge(tre[x].son[0],tre[x].down_tag);
chenge(tre[x].son[1],tre[x].down_tag);
tre[x].down_tag=0;
}
}
IL void rotate(int x)
{
int cdy=tre[x].fa,wzy=tre[tre[x].fa].fa;
int d=tre[tre[x].fa].son[1]==x;int wson=tre[x].son[d^1];
if(!isroot(cdy)) tre[wzy].son[tre[wzy].son[1]==cdy]=x;
tre[x].fa=wzy;tre[cdy].fa=x;tre[x].son[d^1]=cdy;tre[cdy].son[d]=wson;
if(wson) tre[wson].fa=cdy;pushup(cdy);pushup(x);
}
IL void Splay(int x)
{
int cdy=x,wzy=0;top=0;
sta[++top]=cdy;
while(!isroot(cdy)) sta[++top]=cdy=tre[cdy].fa;
while(top>0) down(sta[top--]);
while(!isroot(x))
{
// printf("x x x %d",x);
cdy=tre[x].fa;wzy=tre[tre[x].fa].fa;
if(!isroot(cdy))
{
if((tre[wzy].son[1]==cdy)^(tre[cdy].son[1]==x)) rotate(x);
else rotate(cdy);
}
rotate(x);
}
pushup(x);
}
IL void access(int x)
{
for(R int now=0;x;x=tre[now=x].fa)
{
Splay(x);tre[x].son[1]=now;pushup(x);
}
}
IL void makeroot(int x)
{
access(x);Splay(x);rever(x);
}
IL int findroot(int x)
{
access(x);Splay(x);
while(tre[x].son[0]) down(x),x=tre[x].son[0];
return x;
}
IL void split(int x,int y)
{
makeroot(x);access(y);Splay(y);
}
IL void link(int x,int y)
{
makeroot(x);
if(findroot(y)==x) return;
tre[x].fa=y;
}
IL void cut(int x,int y)
{
makeroot(x);
if(findroot(y)==x&&tre[x].fa==y&&tre[x].son[1]==0)
tre[x].fa=tre[y].son[0]=0;return;
}
IL void add(int x,int y,ll d)
{
makeroot(x);
if(findroot(y)==x)
{
split(x,y);
chenge(y,d);
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen("tmp.out","w",stdout);
read(n);read(m);
for(R int i=1;i<=n;++i) read(tre[i].num),pushup(i);
for(R int i=1,x,y;i<n;++i)
{
read(x);read(y);
link(x,y);
}
while(m--)
{
int knd,x,y;ll d;
read(knd);
if(knd==1)
{
read(x);read(y);
cut(x,y);
}
else if(knd==2)
{
read(x);read(y);
link(x,y);
}
else if(knd==3)
{
read(x);read(y);read(d);
add(x,y,d);
}
else if(knd==4)
{
read(x);read(y);
makeroot(x);
if(findroot(y)==x)
{
split(x,y);
ll cdy=tre[y].val,wzy=(tre[y].siz+1)*tre[y].siz/2;ll tmp=gcd(cdy,wzy);
printf("%lld/%lld\n",cdy/tmp,wzy/tmp);
}
else puts("-1");
}
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
HEOI 2019 RP++
P4842 城市旅行的更多相关文章
- luogu P4842 城市旅行
嘟嘟嘟 好题,好题 刚开始突发奇想写了一个\(O(n ^ 2)\)暴力,结果竟然过了?!后来才知道是上传题的人把单个数据点开成了10s-- 不过不得不说我这暴力写的挺好看的.删边模仿链表删边,加边的时 ...
- 【LCT】BZOJ3091 城市旅行
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1927 Solved: 631[Submit][Status][Discuss ...
- BZOJ 3091: 城市旅行 [LCT splay 期望]
3091: 城市旅行 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1454 Solved: 483[Submit][Status][Discuss ...
- 【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 ...
- 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 1 4 1 4 Sample ...
- 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区间信息合并
题目描述 输入 输出 样例输入 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
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3091 题意概括 鉴于本人语文不好,此题的描述原题很清晰,废话不多,请看原题. 可怕,原题是图片,不 ...
随机推荐
- send anywhere真的好用啊
手机和电脑互传文件,方便很多.
- C#使用互斥量(Mutex)实现多进程并发操作时多进程间线程同步操作(进程同步)的简单示例代码及使用方法
本文主要是实现操作系统级别的多进程间线程同步(进程同步)的示例代码及测试结果.代码经过测试,可供参考,也可直接使用. 承接上一篇博客的业务场景[C#使用读写锁三行代码简单解决多线程并发写入文件时线程同 ...
- 用JQ去实现一个轮播效果
前提:用JQ去实现轮播效果一步步的做一个梳理. 首先肯定是轮播的HTML和CSS样式了: <body> <div class="pic"> <div ...
- 超详细JSON解析步骤
JSON简介 JAVAScript Object Notation是一种轻量级的数据交换格式 具有良好的可读和便于快速编写的特性. 业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了 ...
- awk基础01-基本用法
什么是awk awk 是一门解释型的编程语言,支持条件判断,数组.循环等功能.可用于文本处理.输出格式化的文本信息.执行数学运算.字符串等操作. awk在处理文件时按行进行逐行处理,即 ...
- UVALive - 6434 —(思维题)
题意:给出了你由n个数组成的序列,让你将这个序列分为成m个集合,使得每一个集合的最大值减最小值的差相加最小.(如果某集合只有一个数字,则最大值减最小值为0) . 思路:首先我们不难想到,最优的分配方法 ...
- nancyfx的安装笔记
这个安装时很简单的 只要 Install-Package Nancy.Hosting.Aspnet 就行了. 需要注意的是,千万不要用那个模板安装,通过创建nancyfx类型项目的方式安装是有问题的. ...
- [Erlang31]Erlang trace总结
在一个并行的世界里面,我们很难做到单步断点调试来定位问题(太多的消息飞来飞去),Erlang设计者也深刻体会到这一点,推出了另一个trace机制. 通过这个trace,你可以: .特定进程集内的函数调 ...
- 我对于C#的想法
前言 首先,感谢各位的回答,还看到了好几个大神过来回答受宠若惊,有叫我坚持的,有叫我放弃,感谢. 一开始我学的是Java,但是没有实际的工作经验,因为从工作开始到现在已经两年的时间了我用的一直都是C# ...
- ASP.NET MVC 通过ActionFilterAttribute来实现防止重复提交
实现思想:每个页面打开的时候会在页面的隐藏控件自动生成一个值并将这个值赋值session,当提交方法的时候会在过滤器的时候进行获取session和页面传值过来的隐藏控件的值进行比较,如果值相同的话,重 ...