题目描述

输入

输出

样例输入

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. docker镜像的创建commit及dockerfile

    在docker 1.3版本以前使用attach进入容器会经常出现卡死的情况,之后官方退出了exec命令,从宿主机进入,但是从其他远程主机进入使用ssh服务来维护是用户熟悉的方法.所以这里来创建一个带有 ...

  2. mysql分表操作

    一般分表操作有垂直拆分和水平拆分.顾名思义. 1.  垂直拆分是指,这个表的列,即字段,要拆分成两个或多个表. 这个应用场景比如:这个表字段,几个都是int.datetime等,有那么一个是text类 ...

  3. c#对联合体的封装

    https://blog.csdn.net/u012846041/article/details/37518313 标准C或者C++中均提供关键字定义联合结构,C#中未提供类似的关键字,但仍然可以定义 ...

  4. Python基础(函数,函数的定义,函数的调用,函数的参数,递归函数)

    1.函数 我们知道圆的面积计算公式为: S = πr2 当我们知道半径r的值时,就可以根据公式计算出面积.假设我们需要计算3个不同大小的圆的面积: r1 = 12.34 r2 = 9.08 r3 = ...

  5. java jdk 配置

    1.配置 C:\Program Files\Java\jdk1.8.0_131\bin 路径 到环境变量 Path

  6. 最全的前端Git基础命令,看完保证你会!

    常见信息 master: 默认开发分支 origin:默认远程版本库 Head: 默认开发分支 Head^:Head 的父提交 创建新仓库 git init git init [project-nam ...

  7. [HAOI2017]供给侧改革[离线、trie]

    题意 题目链接 分析 由于数据随机所以 LCP 不会很长,维护每个位置后 40 个字符构成的01串. 将询问离线维护,以当前右端点为 R 的每个长度的 LCP 的第一个出现位置 f(这个信息显然是单调 ...

  8. LeetCode Search Insert Position (二分查找)

    题意 Given a sorted array and a target value, return the index if the target is found. If not, return ...

  9. 没有 iOS 开发者账号的情况下部署到真机的方法

    原文发表于我的技术博客 本文分享了官方推荐的没有 iOS 开发者账号的情况下部署到真机的方法,供参考. 原文发表于我的技术博客 1. 官方推荐的方法 原文在此,也就是 Ionic 官方团队在博客中分享 ...

  10. B. Divisor Subtraction

    链接 [http://codeforces.com/contest/1076/problem/B] 题意 给你一个小于1e10的n,进行下面的运算,n==0 结束,否则n-最小质因子,问你进行多少步 ...