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+1)。

我们在splay树上维护几个值:
sumv=ΣAi*i*(len-i+1)

lsum=ΣAi*i

rsum=ΣAi*(len-i+1)

sum=ΣAi

不难维护者几个变量的关系,打懒标记时快速算一下Σi*(len-i+1)和Σi就行了。

注意flip时要交换两子树的lsum和rsum。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define lc ch[x][0]
#define rc ch[x][1]
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read() {
    int x=0,f=1;char c=Getchar();
    for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
const int maxn=50010;
ll f[maxn],sumv[maxn],sum[maxn],lsum[maxn],rsum[maxn],s[maxn],addv[maxn],val[maxn];
int pre[maxn],fa[maxn],ch[maxn][2],flip[maxn];
void Add(int x,ll v) {
    if(!v||!x) return;
    sumv[x]+=v*f[s[x]];
    lsum[x]+=v*(1+s[x])*s[x]/2;
    rsum[x]+=v*(1+s[x])*s[x]/2;
    sum[x]+=v*s[x];
}
void maintain(int x) {
    if(!x) return;
    s[x]=s[lc]+s[rc]+1;
    sum[x]=sum[lc]+sum[rc]+val[x];
    sumv[x]=sumv[lc]+sumv[rc]+lsum[lc]*(s[rc]+1)+rsum[rc]*(s[lc]+1)+val[x]*(s[lc]+1)*(s[rc]+1);
    lsum[x]=lsum[lc]+lsum[rc]+val[x]*(s[lc]+1)+sum[rc]*(s[lc]+1);
    rsum[x]=rsum[rc]+rsum[lc]+val[x]*(s[rc]+1)+sum[lc]*(s[rc]+1);
    Add(x,addv[x]);
}
void pushdown(int x) {
    if(flip[x]) {
        swap(lc,rc);
        swap(lsum[lc],rsum[lc]);
        swap(lsum[rc],rsum[rc]);
        flip[lc]^=1;flip[rc]^=1;
        flip[x]=0;
    }
    if(addv[x]) {
        val[x]+=addv[x];addv[lc]+=addv[x];addv[rc]+=addv[x];
        Add(lc,addv[x]);Add(rc,addv[x]);addv[x]=0;
    }
}
void rotate(int x) {
    int y=pre[x],z=pre[y],d=ch[y][0]==x;
    ch[y][d^1]=ch[x][d];pre[ch[x][d]]=y;
    ch[z][ch[z][1]==y]=x;pre[x]=z;
    ch[x][d]=y;pre[y]=x;maintain(y);
}
int S[maxn],top;
void splay(int x) {
    for(int i=x;i;i=pre[i]) S[++top]=i;
    if(top!=1) fa[x]=fa[S[top]],fa[S[top]]=0;
    while(top) pushdown(S[top--]);
    while(pre[x]) rotate(x);
    maintain(x);
}
void access(int x) {
    for(int y=0;x;x=fa[x]) {
        splay(x);pre[ch[x][1]]=0;fa[ch[x][1]]=x;
        ch[x][1]=y;pre[y]=x;maintain(y=x);
    }
}
void makeroot(int x) {
    access(x);splay(x);flip[x]^=1;
    maintain(x);
}
int find(int x) {
    access(x);splay(x);
    while(ch[x][0]) x=ch[x][0];
    return x;
}
void link(int x,int y) {
    makeroot(x);fa[x]=y;
}
void cut(int x,int y) {
    makeroot(x);access(y);splay(y);
    if(s[y]==2) {
        pre[ch[y][0]]=0;ch[y][0]=0;
        maintain(y);
    }
}
ll gcd(ll x,ll y) {return !y?x:gcd(y,x%y);}
void query(int x,int y) {
    makeroot(x);access(y);splay(y);
    ll len=s[y]-1;len=(len+1)*(len+2)/2;
    ll ans=sumv[y],t=gcd(len,ans);
    printf("%lld/%lld\n",ans/t,len/t);
}
void update(int x,int y,ll v) {
    makeroot(x);access(y);splay(y);
    addv[y]+=v;Add(y,v);
}
int main() {
    int n=read(),m=read();
    f[1]=1;
    rep(i,2,n) f[i]=f[i-1]+(ll)i*(i-1)/2+i;
    rep(i,1,n) val[i]=read();
    rep(i,1,n-1) link(read(),read());
    while(m--) {
        int t=read(),x=read(),y=read();
        if(t==1) if(find(x)==find(y)) cut(x,y);
        if(t==2) if(find(x)!=find(y)) link(x,y);
        if(t==3) {
            ll v=read();
            if(find(x)==find(y)) update(x,y,v);
        }
        if(t==4) {
            if(find(x)==find(y)) query(x,y);
            else puts("-1");
        }
    }
    return 0;
}

时间: 2024-11-09 05:37:20

BZOJ3091: 城市旅行的相关文章

【LCT】BZOJ3091 城市旅行

3091: 城市旅行 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 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&l

bzoj-3091 城市旅行

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

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$,只需要维护每个子区间的长度之和即可. 考虑如果已经知道了左右子树的信息以及当前节点信息,如何更新当前子树的信息.需要解决

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.询问两点之间路径上任选两点路径上的点权和的期望值 前三个操作都很基础 但是第四个东西--这啥玩应这是-- 首先这个期望值等于路径上所有无序点对路径上权值和的平均值 还是很抽象?没关系,拿样例说话 样例第一个询问

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

对于动态树 (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.景点坐标中可能有重复的