题目描述

输入

输出

样例输入

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<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N

前三个操作都很简单了,LCT就能维护,重点是第四个操作。

求一个区间所有子区间的区间和之和,直接求所有区间和不好求,我们换一种角度去做。

考虑每个点对区间的贡献,假设当前区间是[l,r],对于区间中的点k(l<=k<=r),它的贡献就是它的点权*(k-l+1)*(r-k+1)。

那么我们维护区间答案,考虑怎么上传及修改?

先说上传,就是将一个点的左儿子区间+这个点+这个点的右儿子区间合并。

我们设size[x]为x子树大小,也就是x子树所代表的区间的长度;ls代表左子树,rs代表右子树。

对于左区间,每个点的贡献要加上它从左往右数的排名*它的点权*(1+size[rs])。

对于右区间,每个点的贡献要加上它从右往左数的排名*它的点权*(1+size[ls])。

对于点x要加上它的点权*(1+size[ls])*(1+size[rs])。

发现排名*点权的和无法直接求,因此还要维护两个信息lv[x],rv[x],分别代表x子树所代表区间中每个点点权*从左/从右排名的和。

再看看这两个信息怎么合并,就以lv[x]为例吧,先将左右子节点的lv加上,左子树lv不变,右子树的lv发现每个点排名都加了(1+size[ls]),只要再加上右子树权值和*(1+size[ls])就好了。

综上所述,我们需要维护六个变量val,sum,lv,rv,size,ans,分别代表单点权值、子树权值和、点权*从左数排名之和、点权*从右数排名之和、子树节点数、区间所有子区间和之和即答案。

再说怎么修改?设n代表区间长,v为修改时的增量

val和sum比较常规在这就不说了。

lv和rv都加了

而ans则加了

最后这个推一个通项公式就好了。

知道怎么上传和修改后剩下的就LCT基本操作了。

但要注意翻转时也要把lv和rv交换且旋到原树根的操作splay之后不能只打标记,要先把当前点左右子树翻转,否则当前点的lv和rv是反的。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ls s[rt][0]
#define rs s[rt][1]
using namespace std;
int n,m;
int x,y;
int opt;
ll z;
int r[50010];
int s[50010][2];
int f[50010];
int st[50010];
ll lv[50010];
ll rv[50010];
ll sum[50010];
ll size[50010];
ll val[50010];
ll ans[50010];
ll a[50010];
ll p,q;
ll res;
int get(int rt)
{
return s[f[rt]][1]==rt;
}
int is_root(int rt)
{
return s[f[rt]][1]!=rt&&s[f[rt]][0]!=rt;
}
void add(int rt,ll v)
{
val[rt]+=v;
sum[rt]+=v*size[rt];
lv[rt]+=v*size[rt]*(size[rt]+1)/2;
rv[rt]+=v*size[rt]*(size[rt]+1)/2;
ans[rt]+=v*size[rt]*(size[rt]+1)*(size[rt]+2)/6;
a[rt]+=v;
}
void flip(int rt)
{
swap(ls,rs);
swap(lv[rt],rv[rt]);
r[rt]^=1;
}
void pushup(int rt)
{
size[rt]=size[ls]+size[rs]+1;
sum[rt]=sum[ls]+sum[rs]+val[rt];
lv[rt]=lv[ls]+lv[rs]+(val[rt]+sum[rs])*(size[ls]+1);
rv[rt]=rv[ls]+rv[rs]+(val[rt]+sum[ls])*(size[rs]+1);
ans[rt]=ans[ls]+ans[rs]+val[rt]*(size[ls]+1)*(size[rs]+1)+lv[ls]*(size[rs]+1)+rv[rs]*(size[ls]+1);
}
void pushdown(int rt)
{
if(r[rt])
{
r[rt]^=1;
flip(ls);
flip(rs);
}
if(a[rt])
{
add(ls,a[rt]);
add(rs,a[rt]);
a[rt]=0;
}
}
void rotate(int rt)
{
int fa=f[rt];
int anc=f[fa];
int k=get(rt);
if(!is_root(fa))
{
s[anc][get(fa)]=rt;
}
s[fa][k]=s[rt][k^1];
f[s[fa][k]]=fa;
s[rt][k^1]=fa;
f[fa]=rt;
f[rt]=anc;
pushup(fa);
pushup(rt);
}
void splay(int rt)
{
int top=0;
st[++top]=rt;
for(int i=rt;!is_root(i);i=f[i])
{
st[++top]=f[i];
}
for(int i=top;i>=1;i--)
{
pushdown(st[i]);
}
for(int fa;!is_root(rt);rotate(rt))
{
if(!is_root(fa=f[rt]))
{
rotate(get(fa)==get(rt)?fa:rt);
}
}
}
void access(int rt)
{
for(int x=0;rt;x=rt,rt=f[rt])
{
splay(rt);
s[rt][1]=x;
pushup(rt);
}
}
void reverse(int rt)
{
access(rt);
splay(rt);
flip(rt);
}
void link(int x,int y)
{
reverse(x);
f[x]=y;
}
void cut(int x,int y)
{
reverse(x);
access(y);
splay(y);
if(s[x][1]||f[x]!=y)
{
return ;
}
s[y][0]=f[x]=0;
pushup(y);
}
void change(int x,int y,ll z)
{
reverse(x);
access(y);
splay(y);
add(y,z);
}
int find(int rt)
{
while(f[rt])
{
rt=f[rt];
}
return rt;
}
void split(int x,int y)
{
reverse(x);
access(y);
splay(y);
}
ll gcd(ll x,ll y)
{
if(y==0)
{
return x;
}
return gcd(y,x%y);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&val[i]);
pushup(i);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
link(x,y);
}
while(m--)
{
scanf("%d%d%d",&opt,&x,&y);
if(opt==1)
{
if(find(x)==find(y))
{
cut(x,y);
}
}
else if(opt==2)
{
if(find(x)!=find(y))
{
link(x,y);
}
}
else if(opt==3)
{
scanf("%lld",&z);
if(find(x)==find(y))
{
split(x,y);
add(y,z);
}
}
else
{
if(find(x)==find(y))
{
split(x,y);
p=ans[y];
q=size[y]*(size[y]+1)/2;
res=gcd(p,q);
printf("%lld/%lld\n",p/res,q/res);
}
else
{
printf("-1\n");
}
}
}
}

BZOJ3091城市旅行——LCT区间信息合并的更多相关文章

  1. bzoj3091 城市旅行 LCT + 区间合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3091 题解 调了整个晚自习才调出来的问题. 乍一看是个 LCT 板子题. 再看一眼还是个 LC ...

  2. 【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 题解 LCT区间合并 前三个 ...

  3. BZOJ3091 城市旅行 LCT

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3091 题意概括 鉴于本人语文不好,此题的描述原题很清晰,废话不多,请看原题. 可怕,原题是图片,不 ...

  4. BZOJ3091: 城市旅行(LCT,数学期望)

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

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

  6. 【LCT】BZOJ3091 城市旅行

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

  7. bzoj 3091: 城市旅行 LCT

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

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

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

  9. 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 ...

随机推荐

  1. nginx-haproxy-lvs功能和性能对比 nginx - max-fail + 调度算法

    优点(性能和功能两方面分析) 缺点 lvs 工作在4层,可以对http,MySQL等服务负载均衡.负责流量的分发,对io,cpu,mem的消耗少 功能比较少,没有正则匹配的功能 nginx 工作在7层 ...

  2. LED灯珠散热的计算方法

    LED灯珠散热的计算方法 来源: 时间:2014-09-23 13:55 [编辑:lufieliu] [字体:大 中 小] 我来说两句   一.热对LED的影响 1.LED是冷光源吗? (1)LED的 ...

  3. 在oj中Python的循环输入问题解决

    在oj中Python的循环输入问题解决 在makefile中定义逗号字符串和空格字符串 在linux服务器上面部署javaweb项目jar包 数据结构与算法之栈(Java与Python实现) 在oj中 ...

  4. VMware Ubuntu蓝屏问题解决

    解决方法: 问题分析启动 Ubuntu 可以进入登录界面,说明系统是可以运行起来的.没有发生大块的核心数据损坏,linux 系统一般都可以修复,一定要淡定.于是开始放狗(google)搜索.“VMwa ...

  5. python中和生成器协程相关yield from之最详最强解释,一看就懂(二)

    一. 从列表中yield  语法形式:yield from <可迭代的对象实例> python中的列表是可迭代的, 如果想构造一个生成器逐一产生list中元素,按之前的yield语法,是在 ...

  6. System.Data.SqlClient.SqlException:“对象名 'customer' 无效。"

    连接数据库出错, 错误原因:表名错误.

  7. B. Vova and Trophies

    链接 [https://codeforces.com/contest/1082/problem/B] 题意 给你一个包含GS的字符串,只允许交换一次任意不同位置的字符,问最长的连续G串是多少 分析 很 ...

  8. PairProject-电梯调度程序结对编程

    结对编程人员:184/050 1 结对编程 1.1 结对编程的优缺点 优点: ● 与单独开发相比,结对能够使人们在压力之下保持更好的状态.结对编程鼓励双方保持代码的高质量,即使在出现了让人不得不飞快地 ...

  9. myeclipse快捷方式汇总

    选择你要注释的那一行或多行代码,按Ctrl+/即可,取消注释也是选中之后按Ctrl+/即可. 如果你想使用的快捷键的注释是的话,那么你的快捷键是ctrl+shift+/我以前都是手动注释的,直接打// ...

  10. 软件工程——移动的HelloWorld

    package disiti;       import java.awt.Color;   import java.awt.Cursor;   import java.awt.Font;   imp ...