洛谷P4219 - [BJOI2014]大融合

Portal

Description

初始有\(n(n\leq10^5)\)个孤立的点,进行\(Q(Q\leq10^5)\)次操作:

  • 连接边\((u,v)\),保证\(u,v\)不连通。
  • 询问有多少条简单路径经过边\((u,v)\)。

Solution

加边用lct,询问结果相当于\(p\)为根时的\((siz[p]-siz[q])\times siz[q]\)。

那么如何用lct维护子树大小呢?维护\(isiz[p]\)表示\(p\)在lct上的虚子树大小,\(siz[p]\)表示\(isiz[p]\)加上在辅助树上的实子树大小(子树大小也包括子树的虚子树和实子树)。当\(p=rt\)或\(p\)没有实子树时,\(siz[p]\)等于其原树上的子树大小。

如何维护\(isiz\)呢?只有当树的虚实划分变化时,\(isiz\)才会变化,也就是accesslinkaccess(p)中有一句ch[p][1]=q,说明\(ch[p][1]\)变为虚子树,\(q\)变为实子树,则isiz[p]+=siz[ch[p][1]]-siz[q]link(p,q)将\(p\)变为\(q\)的虚子树,因此\(q\)到\(q\)的根的\(isiz\)都要改变;因为不好实现所以makeRt(q)之后再连接,并isiz[q]+=siz[p]

询问时,只要makeRt(p),access(q),splay(q),此时\(q=rt\),\(p\)没有实子树,\(siz\)均正确。

时间复杂度\(O(Qlogn)\)。

Code

//[BJOI2014]大融合
#include <cstdio>
#include <algorithm>
using namespace std;
int read()
{
    int x=0; char ch=getchar();
    while(ch<‘0‘||‘9‘<ch) ch=getchar();
    while(‘0‘<=ch&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x;
}
int const N=1e5+10;
int n,Q;
int fa[N],ch[N][2],siz[N],isiz[N]; bool rev[N];
int wh(int p) {return p==ch[fa[p]][1];}
int notRt(int p) {return p==ch[fa[p]][wh(p)];}
void rever(int p) {rev[p]^=1; swap(ch[p][0],ch[p][1]);}
void update(int p) {siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+isiz[p]+1;}
void pushdw(int p) {if(rev[p]) rever(ch[p][0]),rever(ch[p][1]),rev[p]=false;}
void rotate(int p)
{
    int q=fa[p],r=fa[q],w=wh(p);
    fa[p]=r; if(notRt(q)) ch[r][wh(q)]=p;
    fa[ch[q][w]=ch[p][w^1]]=q;
    fa[ch[p][w^1]=q]=p;
    update(q),update(p);
}
void pushdwRt(int p) {if(notRt(p)) pushdwRt(fa[p]); pushdw(p);}
void splay(int p)
{
    pushdwRt(p);
    for(int q=fa[p];notRt(p);rotate(p),q=fa[p]) if(notRt(q)) rotate(wh(p)^wh(q)?p:q);
}
void access(int p) {for(int q=0;p;q=p,p=fa[p]) splay(p),isiz[p]+=siz[ch[p][1]]-siz[q],ch[p][1]=q,update(p);}
void makeRt(int p) {access(p),splay(p),rever(p);}
void link(int p,int q) {makeRt(p),makeRt(q); fa[p]=q,isiz[q]+=siz[p]; update(q);}
long long query(int p,int q) {makeRt(p),access(q),splay(q); return (long long)siz[p]*(siz[q]-siz[p]);}
int main()
{
    n=read(),Q=read();
    for(int i=1;i<=n;i++) siz[i]=1;
    for(int i=1;i<=Q;i++)
    {
        char opt[5]; scanf("%s",opt);
        int u=read(),v=read();
        if(opt[0]==‘A‘) link(u,v);
        else printf("%lld\n",query(u,v));
    }
    return 0;
}

P.S.

比Icefox短了20行!

原文地址:https://www.cnblogs.com/VisJiao/p/LgP4219.html

时间: 2024-10-11 11:24:03

洛谷P4219 - [BJOI2014]大融合的相关文章

洛谷P4219 [BJOI2014]大融合(LCT,Splay)

LCT维护子树信息的思路总结与其它问题详见我的LCT总结 思路分析 动态连边,LCT题目跑不了了.然而这题又有点奇特的地方. 我们分析一下,查询操作就是要让我们求出砍断这条边后,x和y各自子树大小的乘积. 掌握了LCT如何维护虚子树信息和后,做法就很清晰了.split(x,y)后,输出x的虚子树和+1与y的虚子树和+1的乘积:或者,(以y为根)输出x的子树总和与y的子树总和减去x的子树总和的乘积. 代码如下(这次我试着写了一个单旋"Spaly",好像常数还小不少......) #inc

P4219 [BJOI2014]大融合(LCT)

P4219 [BJOI2014]大融合 对于每个询问$(u,v)$所求的是 ($u$的虚边子树大小+1)*($v$的虚边子树大小+1) 于是我们再开个$si[i]$数组表示$i$的虚边子树大小,维护一下就好辣 #include<iostream> #include<cstdio> #include<cstring> using namespace std; inline void Swap(int &a,int &b){a^=b^=a^=b;} void

P4219 [BJOI2014]大融合

传送门 动态维护森林 显然考虑 $LCT$ 但是发现询问求的是子树大小,比较不好搞 维护 $sum[x]$ 表示节点 $x$ 的子树大小,$si[x]$ 表示 $x$ 的子树中虚儿子的子树大小和 那么 $pushup$ 可以这样写: inline void pushup(int x) { sum[x]=sum[c[x][0]]+sum[c[x][1]]+si[x]+1; } 考虑什么时候 $si$ 会变 首先对于 $rotate,splay$ 因为都是对一条实链搞,所以对虚边没影响 然后考虑 $

BZOJ:4530: [Bjoi2014]大融合

4530: [Bjoi2014]大融合 拿这题作为lct子树查询的练手.本来以为这会是一个大知识点,结果好像只是一个小技巧? 多维护一个虚边连接着的子树大小即可. #include<cstdio> #include<cstring> #include<algorithm> #define MN 210010 using namespace std; int p,ca,f; inline int read(){ p=0;ca=getchar();f=1; while(ca

BJOI2014 大融合

3766. [BJOI2014]大融合 (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB Description 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树.这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量. 例如,在上图中,现在一共有了5条边.其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8

洛谷 P1230 智力大冲浪

我的第一篇题解(辣鸡题解)洛谷 P1230 智力大冲浪 题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元.先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则: 首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n).如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的.当然,每个游

洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不同树的影响. 假设有一个2操作形如\(l\ r\ x\),那么从微观来看差异,我们只关注第l-1棵树和第l棵树.再假设以后都没有了1操作,那么我们可以认为,第l棵树是第l-1棵树把这个1操作以后嫁接在原来生长节点上的所有节点(以及所有子树)全部转而嫁接到x上.再看第r棵树和第r+1棵树,是不是可以认

洛谷P1230 智力大冲浪

题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元.先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则: 首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n).如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的.当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且

AC日记——神奇的幻方 洛谷 P2615(大模拟)

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)