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

3091: 城市旅行

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N

Source

wyx528命题



谜一般的翻转标记

大爷题解传送门:http://blog.csdn.net/popoqqq/article/details/40823659

与上一题不一样的是,每个点在链上的位置不一定,所以没法维护vi*i之类的东西,只能像那样记录lsum和rsum然后update的时候处理

本题的翻转标记必须立即生效,因为反转标记还会影响lsum和rsum

除了一开始就Link外,还可以保存图然后dfs只设置fa关系不用Link,然而并没有带来常数提升反而更慢了...

BZOJ 100题达成

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=5e4+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}

struct node{
    int ch[2],fa,rev;
    ll add,lsum,rsum,sum,exp,w,size;
}t[N];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void update(int x){
    t[x].size=t[lc].size+t[rc].size+1;
    t[x].sum=t[lc].sum+t[rc].sum+t[x].w;
    t[x].lsum=t[lc].lsum+t[x].w*(t[lc].size+1)+t[rc].lsum+t[rc].sum*(t[lc].size+1);
    t[x].rsum=t[rc].rsum+t[x].w*(t[rc].size+1)+t[lc].rsum+t[lc].sum*(t[rc].size+1);
    t[x].exp=t[lc].exp+t[rc].exp
    +t[lc].lsum*(t[rc].size+1)+t[rc].rsum*(t[lc].size+1)
    +t[x].w*(t[lc].size+1)*(t[rc].size+1);
}
inline ll cal1(ll x){return x*(x+1)/2;}
inline ll cal2(ll x){return x*(x+1)*(x+2)/6;}
inline void paint(int x,ll d){
    t[x].w+=d;
    t[x].add+=d;
    t[x].sum+=d*t[x].size;
    t[x].lsum+=d*cal1(t[x].size);
    t[x].rsum+=d*cal1(t[x].size);
    t[x].exp+=d*cal2(t[x].size);
}
inline void rever(int x){
    swap(lc,rc);
    swap(t[x].lsum,t[x].rsum);
    t[x].rev^=1;
}
inline void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);//!!!!!
        t[x].rev=0;
    }
    if(t[x].add){
        paint(lc,t[x].add);
        paint(rc,t[x].add);
        t[x].add=0;
    }
}

inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);

    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}

inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeR(int x){
    Access(x);splay(x);
    rever(x);
}
inline int FindR(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeR(x);
    t[x].fa=y;
}
inline void Cut(int x,int y){
    MakeR(x);Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
    update(y);//!!!
}
inline void Add(int x,int y,int d){
    if(FindR(x)!=FindR(y)) return;
    MakeR(x);Access(y);splay(y);
    paint(y,d);
}
inline ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
inline void Que(int x,int y){
    if(FindR(x)!=FindR(y)){puts("-1");return;}
    MakeR(x);Access(y);splay(y);
    ll a=t[y].exp,b=t[y].size*(t[y].size+1)/2;
    ll g=gcd(a,b);//printf("Que %d %d %d\n",a,b,g);
    printf("%lld/%lld\n",a/g,b/g);
}
int n,Q,a,op,x,y,d;
int main(){
    n=read();Q=read();
    for(int i=1;i<=n;i++){
        a=read();
        t[i].size=1;
        t[i].w=t[i].lsum=t[i].rsum=t[i].sum=t[i].exp=a;
    }
    for(int i=1;i<=n-1;i++) x=read(),y=read(),Link(x,y);
    while(Q--){
        op=read();x=read();y=read();
        if(op==1) if(FindR(x)==FindR(y)) Cut(x,y);
        if(op==2) if(FindR(x)!=FindR(y)) Link(x,y);
        if(op==3) d=read(),Add(x,y,d);
        if(op==4) Que(x,y);
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=5e4+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}

struct node{
    int ch[2],fa,rev;
    ll add,lsum,rsum,sum,exp,w,size;
}t[N];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void update(int x){
    t[x].size=t[lc].size+t[rc].size+1;
    t[x].sum=t[lc].sum+t[rc].sum+t[x].w;
    t[x].lsum=t[lc].lsum+t[x].w*(t[lc].size+1)+t[rc].lsum+t[rc].sum*(t[lc].size+1);
    t[x].rsum=t[rc].rsum+t[x].w*(t[rc].size+1)+t[lc].rsum+t[lc].sum*(t[rc].size+1);
    t[x].exp=t[lc].exp+t[rc].exp
    +t[lc].lsum*(t[rc].size+1)+t[rc].rsum*(t[lc].size+1)
    +t[x].w*(t[lc].size+1)*(t[rc].size+1);
}
inline ll cal1(ll x){return x*(x+1)/2;}
inline ll cal2(ll x){return x*(x+1)*(x+2)/6;}
inline void paint(int x,ll d){
    t[x].w+=d;
    t[x].add+=d;
    t[x].sum+=d*t[x].size;
    t[x].lsum+=d*cal1(t[x].size);
    t[x].rsum+=d*cal1(t[x].size);
    t[x].exp+=d*cal2(t[x].size);
}
inline void rever(int x){
    swap(lc,rc);
    swap(t[x].lsum,t[x].rsum);
    t[x].rev^=1;
}
inline void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);//!!!!!
        t[x].rev=0;
    }
    if(t[x].add){
        paint(lc,t[x].add);
        paint(rc,t[x].add);
        t[x].add=0;
    }
}

inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);

    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}

inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeR(int x){
    Access(x);splay(x);
    rever(x);
}
inline int FindR(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeR(x);
    t[x].fa=y;
}
inline void Cut(int x,int y){
    MakeR(x);Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
    update(y);//!!!
}
inline void Add(int x,int y,int d){
    if(FindR(x)!=FindR(y)) return;
    MakeR(x);Access(y);splay(y);
    paint(y,d);
}
inline ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
inline void Que(int x,int y){
    if(FindR(x)!=FindR(y)){puts("-1");return;}
    MakeR(x);Access(y);splay(y);
    ll a=t[y].exp,b=t[y].size*(t[y].size+1)/2;
    ll g=gcd(a,b);//printf("Que %d %d %d\n",a,b,g);
    printf("%lld/%lld\n",a/g,b/g);
}
int n,Q,a,op,x,y,d;

struct edge{
    int v,ne;
}e[N<<1];
int cnt,h[N];
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
inline void dfs(int u,int fa){
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].v!=fa){
            t[e[i].v].fa=u;
            dfs(e[i].v,u);
        }
}
int main(){
    n=read();Q=read();
    for(int i=1;i<=n;i++){
        a=read();
        t[i].size=1;
        t[i].w=t[i].lsum=t[i].rsum=t[i].sum=t[i].exp=a;
    }
    for(int i=1;i<=n-1;i++) x=read(),y=read(),ins(x,y);
    dfs(1,0);
    while(Q--){
        op=read();x=read();y=read();
        if(op==1) if(FindR(x)==FindR(y)) Cut(x,y);
        if(op==2) if(FindR(x)!=FindR(y)) Link(x,y);
        if(op==3) d=read(),Add(x,y,d);
        if(op==4) Que(x,y);
    }
}
时间: 2024-10-18 08:40:09

BZOJ 3091: 城市旅行 [LCT splay 期望]的相关文章

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

BZOJ 3091 城市旅行 Link-Cut-Tree

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

【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 2843: 极地旅行社 lct splay

http://www.lydsy.com/JudgeOnline/problem.php?id=2843 https://blog.csdn.net/clove_unique/article/details/50992341 和之前那道题lct求两点距离用lca不同,这道题因为给的边的两个端点是没有顺序的(没法直接按照给的点直接将某个点连到树上),所以bridge需要区间翻转的操作,因为splay维护的是链,所以区间翻转相当于将叶子变成了根,根变成叶子(链翻转过来),然后再把此时的根(x)连到y

【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 3779 重组病毒 LCT+线段树(维护DFS序)

原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核

[BZOJ 3531] [Sdoi2014] 旅行 【离线+LCT】

题目链接:BZOJ - 3531 题目分析 题目询问一条路径上的信息时,每次询问有某种特定的文化的点. 每个点的文化就相当于一种颜色,每次询问一条路径上某种颜色的点的信息. 可以使用离线算法, 类似于“郁闷的小 J ” 那道题目.将各种操作和询问按照颜色为第一关键字,时间为第二关键字排序. 那么修改颜色的操作就相当于在原颜色中是删点,在新颜色中是加点. 处理完一种颜色的操作后,要将这个颜色的点都做一次删除操作,这样,对于处理下一种颜色,树就又是空的了. 这种题,思考的时候有点晕,写代码的时候非常

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 3531 [Sdoi2014]旅行(树链剖分,线段树)

3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 876  Solved: 446[Submit][Status][Discuss] Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用不同的正整数代表 各种宗教,  S国的居民常常旅行.旅行时他们总