【LCT】BZOJ3091 城市旅行

3091: 城市旅行

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1927  Solved: 631
[Submit][Status][Discuss]

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

题解

这题和BZOJ2752类似,只不过那个是在序列上而这个在链上,所以没做过2752的话可以先看看这里

我们发现每次询问其实就是算每个点对答案的贡献/C(n+1,2),也就是/(n+1)*n/2

所以每次只需要单独算每个点的贡献即可

然后每个点对答案的贡献就是a[i]*i*(n-i+1)

所以我们维护一个sum,一个siz,一个L=a[i]*i,一个R=a[i]*(n-i+1)

转移挺好想的(逃

代码(WA???)

//by 减维
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<bitset>
#include<set>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<ctime>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define mpr make_pair
#define maxn 70005
#define inf (1<<30)
#define eps 1e-8
#define pi 3.1415926535897932384626
using namespace std;

inline int read()
{
    int ret=0;bool fla=0;char ch=getchar();
    while((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘)ch=getchar();
    if(ch==‘-‘){fla=1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){ret=ret*10+ch-‘0‘;ch=getchar();}
    return fla?-ret:ret;
}

ll n,m,fa[maxn],son[maxn][2],siz[maxn],val[maxn],sum[maxn],rev[maxn],mar[maxn],L[maxn],R[maxn],ans[maxn];

il ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
il bool pdp(int x){return son[fa[x]][1]==x;}
il bool isrt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
il void rever(int x){rev[x]^=1;swap(son[x][0],son[x][1]);swap(L[x],R[x]);}

il void upda(int x)
{
    siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
    sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];
    ans[x]=ans[son[x][0]]+ans[son[x][1]]+val[x]*(siz[son[x][0]]+1)*(siz[son[x][1]]+1)+L[son[x][0]]*(siz[son[x][1]]+1)+R[son[x][1]]*(siz[son[x][0]]+1);
    L[x]=L[son[x][0]]+L[son[x][1]]+val[x]*(siz[son[x][0]]+1)+sum[son[x][1]]*(siz[son[x][0]]+1);
    R[x]=R[son[x][1]]+R[son[x][0]]+val[x]*(siz[son[x][1]]+1)+sum[son[x][0]]*(siz[son[x][1]]+1);
}

il void add(int x,ll y)
{
    mar[x]+=y;
    val[x]+=y;
    sum[x]+=y;
    ans[x]+=y*(siz[x]+1)*(siz[x]+2)*siz[x]/6;
    L[x]+=y*(siz[x]+1)*siz[x]/2;
    R[x]+=y*(siz[x]+1)*siz[x]/2;
}

il void pdn(int x)
{
    if(rev[x])
    {
        if(son[x][0]) rever(son[x][0]);
        if(son[x][1]) rever(son[x][1]);
        rev[x]=0;
    }
    if(mar[x])
    {
        if(son[x][0]) add(son[x][0],mar[x]);
        if(son[x][1]) add(son[x][1],mar[x]);
        mar[x]=0;
    }
}

il void pd(int x){if(!isrt(x)) pd(fa[x]);pdn(x);}

il void rot(int x)
{
    int f=fa[x],g=fa[f],o=pdp(x);
    if(!isrt(f)) son[g][pdp(f)]=x;fa[x]=g;
    son[f][o]=son[x][!o];fa[son[f][o]]=f;
    son[x][!o]=f;fa[f]=x;
    upda(f),upda(x);
}

il void splay(int x)
{
    pd(x);
    for(;!isrt(x);rot(x))
        if(!isrt(fa[x])) rot(pdp(fa[x])==pdp(x)?fa[x]:x);
}

il void acc(int x)
{
    for(int y=0;x;y=x,x=fa[x])
        splay(x),son[x][1]=y,upda(x);
}

il int find(int x)
{
    acc(x);splay(x);
    while(son[x][0]) pdn(x),x=son[x][0];
    return x;
}

il void bert(int x){acc(x);splay(x);rever(x);}
il void spli(int x,int y){bert(x);acc(y);splay(y);}
il void cut(int x,int y){spli(x,y);fa[x]=son[y][0]=0;upda(y);}
il void link(int x,int y){bert(x);fa[x]=y;}

void dfs(int x)
{
    if(son[x][0]) dfs(son[x][0]);
    printf("%d ",x);
    if(son[x][1]) dfs(son[x][1]);
}

void dfs2(int x)
{
    if(son[x][0]) dfs2(son[x][0]);
    printf("%d ",sum[x]);
    if(son[x][1]) dfs2(son[x][1]);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i) val[i]=read();
    for(int i=1,x,y;i<n;++i) x=read(),y=read(),link(x,y);
    for(int i=1,op,x,y,d;i<=m;++i)
    {
        op=read();x=read();y=read();
        if(op==1){
            if(find(x)==find(y)) cut(x,y);
        }else if(op==2){
            if(find(x)!=find(y)) link(x,y);
        }else if(op==3){
            d=read();
            spli(x,y);add(y,d);
        }else{
            if(find(x)!=find(y)) puts("-1");
            else spli(x,y),printf("%lld/%lld\n",ans[y]/gcd(ans[y],siz[y]*(siz[y]+1)/2),(siz[y]+1)*siz[y]/2/gcd(ans[y],siz[y]*(siz[y]+1)/2));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/rir1715/p/8277830.html

时间: 2024-08-02 12:49:23

【LCT】BZOJ3091 城市旅行的相关文章

bzoj-3091 城市旅行

题意: 给出一颗树,点上有初始权值,有四种操作: 1.加一条边: 2.删一条边: 3.一条路径上的点都加一个权值: 4.查询一条路径上任取两个点的路径上期望权值和: 题解: 本题是2752的升级版,一些公式之类的东西参照上题: 到了树上之后,实际上本质的公式是没有变的,只有一些外在的形式改变了: 因为Splay维护的是树上的重链,那么结点维护的就是链上的答案等东西: 转移一样但是有几点注意: 这里选取的两个点可以相等,所以总方案数是n*(n+1)/2: 换根反转区间时,L[x]和R[x]要相应改

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 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 恶心的动态树上维护各种信息. 不难发现ans=ΣAi*i*(len-i+

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

3091: 城市旅行 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1454  Solved: 483[Submit][Status][Discuss] 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&l

【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区间合并 前三个操作都是LCT的基本操作,可以LCT水过:重点在于第四个操作. 考虑一个长度为n的序列,它的子区间个数为$\sum\limits_{i=1}^ni=\frac{n(n-1)}2$,只需要维护每个子区间的长度之和即可. 考虑如果已经知道了左右子树的信息以及当前节点信息,如何更新当前子树的信息.需要解决

BZOJ 3091: 城市旅行 lct 期望 splay

https://www.lydsy.com/JudgeOnline/problem.php?id=3091 https://blog.csdn.net/popoqqq/article/details/40823659 看题解吧,没什么好解释的....板子题, 我觉得以后我写lct都可以像这样专门写个rev和add的函数出来,很好用. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #incl

P4842 城市旅行

$ \color{#0066ff}{ 题目描述 }$ W国地人物博,有n座城市组成,共n-1条双向道路连接其中的两座城市,且任意两座城市都可相互到达. 风景秀美的w国吸引了无数慕名而来的游客,根据游客对每座城市的打分,我们定义第i座城市的美丽度为\(a_i\).一次从城市x到城市y的旅行,所获得的的偷悦指数为从城市x到城市y所有城市的美丽度之和(包括X和y).我们诅义这个值为H(x,y). 现在小A在城市X,Sharon在城市Y,他们想知道如果在城市X到城市Y之间的所有城市中任选两座城市x和y(

BZOJ 3091 城市旅行 Link-Cut-Tree

警告:此题不可以使用cout进行输出,只能用printf,否则RE!亲测!! 题目大意:给定一棵树,每个点有一个点权,提供四种操作: 1.删除两点之间的连边 不存在边则无视 2.在两点之前连接一条边 两点已经联通则无视 3.在两点之间的路径上所有点的点权加上一个数 两点不连通则无视 4.询问两点之间路径上任选两点路径上的点权和的期望值 前三个操作都很基础 但是第四个东西--这啥玩应这是-- 首先这个期望值等于路径上所有无序点对路径上权值和的平均值 还是很抽象?没关系,拿样例说话 样例第一个询问

对于动态树 (Link-Cut-Tree, LCT) 的理解与总结

原文链接http://www.cnblogs.com/zhouzhendong/p/8424570.html 对于动态树 $(Link-Cut-Tree, LCT)$ 的理解与总结 问题模型 有$n$个节点,每个节点有权值$v_i$,现在有$m$个操作,操作有可能是以下$4$种类型: $1$   -   连接两个节点 $2$   -   断开两个节点之间的边 $3$   -   修改某一个节点的权值 $4$   -   询问两点之间的节点权值和 保证操作和询问合法,并且输入数据保证任何时刻图中不

nyoj253LK的旅行(旋转卡壳法)

LK的旅行 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 LK最近要去某几个地方旅行,她从地图上计划了几个点,并且用笔点了出来,准备在五一假期去这几个城市旅行.现在希望你找出她点的所有的点中距离最远的两个点的距离是多少.各个景点可以认为是在一个平面上. 输入 第一行有一个整数0<n<10表示测试数据的组数随后的n组数据中,第一行有一个整数3<m<100000表示有m个旅游景点.随后的m行每行有两个整数,分别表示每一个点的x和y.景点坐标中可能有重复的