LuoguP4219 [BJOI2014]大融合(LCT)

早上考试想用\(LCT\)维护联通块\(size\),现在才发现\(LCT\)的\(size\)有虚实之分
\(Link\)与\(Acess\)中虚实变,干他丫的
\(Splay\)中只是相对关系,没有虚实变,因此不搞它

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define R(a,b,c) for(register int a = (b); a <= (c); ++a)
#define nR(a,b,c) for(register int a = (b); a >= (c); --a)
#define Fill(a,b) memset(a, b, sizeof(a))
#define Swap(a,b) ((a) ^= (b) ^= (a) ^= (b))

#define ON_DEBUGG

#ifdef ON_DEBUGG

#define D_e_Line printf("-----------\n")
#define D_e(x) std::cout << (#x) << " : " <<x << "\n"
#define FileOpen() freopen("in.txt", "r", stdin)
#define FileSave() freopen("out.txt", "w", stdout)
#define Pause() system("pause")
#include <ctime>
#define TIME() fprintf(stderr, "\nTIME : %.3lfms\n", clock() * 1000.0 / CLOCKS_PER_SEC)

#else

#define D_e_Line ;
#define D_e(x) ;
#define FileOpen() ;
#define FilSave ;
#define Pause() ;
#define TIME() ;

#endif

struct ios {
    template<typename ATP> ios& operator >> (ATP &x) {
        x = 0; int f = 1; char c;
        for(c = getchar(); c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
        while(c >= '0' && c <= '9') x = x * 10 + (c ^ '0'), c = getchar();
        x *= f;
        return *this;
    }
}io;

using namespace std;

template<typename ATP> inline ATP Min(ATP a, ATP b) {
    return a < b ? a : b;
}
template<typename ATP> inline ATP Max(ATP a, ATP b) {
    return a > b ? a : b;
}
template<typename ATP> inline ATP Abs(ATP a) {
    return a < 0 ? -a : a;
}

const int N = 1e5 + 7;

struct LCT {
    int ch[2], fa, siz, sz; // siz : true edge, sz : virtual edge
    bool rev;
} t[N];
#define ls t[u].ch[0]
#define rs t[u].ch[1]
inline int Ident(int &u) {
    return t[t[u].fa].ch[1] == u;
}

inline bool IsRoot(int &u) {
    return t[t[u].fa].ch[0] != u && t[t[u].fa].ch[1] != u;
}

inline void Pushup(int &u) {
    if(u) t[u].siz = t[ls].siz + t[rs].siz + t[u].sz + 1;
    // left + right + virtual + self
}

inline void Pushrev(int u) {
    Swap(ls, rs);
    t[u].rev ^= 1;
}

inline void Pushdown(int u) {
    if(!t[u].rev) return;
    if(ls) Pushrev(ls);
    if(rs) Pushrev(rs);
    t[u].rev = 0;
}

inline void Rotate(int x) {
    int y = t[x].fa, z = t[y].fa, k = Ident(x);
    t[x].fa = z; if(!IsRoot(y)) t[z].ch[Ident(y)] = x;
    t[y].ch[k] = t[x].ch[k ^ 1], t[t[x].ch[k ^ 1]].fa = y;
    t[x].ch[k ^ 1] = y, t[y].fa = x;
    Pushup(y), Pushup(x);
}

int sta[N], top;

inline void Splay(int u) {
    int x = u;
    while(!IsRoot(u)){
        sta[++top] = u;
        u = t[u].fa;
    }
    sta[++top] = u;
    while(top) Pushdown(sta[top--]);
    while(!IsRoot(x)){
        int y = t[x].fa;
        if(!IsRoot(y)){
            Ident(x) == Ident(y) ? Rotate(y) : Rotate(x);
        }
        Rotate(x);
    }
    Pushup(x);
}

inline void Access(int u) {
    for(register int v = 0; u; v = u, u = t[u].fa){
        Splay(u);
        t[u].sz += t[rs].siz - t[v].siz;
        t[u].ch[1] = v;
        Pushup(u);
    }
}

inline void MakeRoot(int u) {
    Access(u);
    Splay(u);
    Pushrev(u);
}

inline void Split(int u, int v) {
    MakeRoot(u);
    Access(v);
    Splay(v);
}

inline void Link(int u, int v) {
    Split(u, v);
    t[u].fa = v;
    t[v].sz += t[u].siz;
}
inline long long Query(int u, int v) {
    Split(u, v);
    return 1ll * (t[u].sz + 1) * (t[v].sz + 1);
}

//inline void Link(int u, int v) {
//  MakeRoot(u);
//  MakeRoot(v);
//  t[u].fa = v;
//  t[v].sz += t[u].siz;
//  Pushup(v);
//}
//inline long long Query(int u, int v) {
//  MakeRoot(u);
//  MakeRoot(v);
//  return 1ll * (t[u].sz + 1) * (t[v].sz + 1);
//}

char opt[13];
int main() {
    int n, m;
    io >> n >> m;
    R(i,1,n){
        t[i].siz = 1;
        t[i].sz = 0;
    }
    while(m--){
        scanf("%s", opt + 1);
        int x, y;
        io >> x >> y;
        if(opt[1] == 'A'){
            Link(x, y);
        }
        else{
            printf("%lld\n", Query(x, y));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bingoyes/p/11721207.html

时间: 2024-07-29 02:03:48

LuoguP4219 [BJOI2014]大融合(LCT)的相关文章

【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量. 例如,在上图中,现在一共有了5条边.其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8). 现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问. 输入 第一行包含两个整数N,Q,表示星球的

Luogu4219 BJOI2014 大融合 LCT

传送门 题意:写一个数据结构,支持图上连边(保证图是森林)和询问一条边两端的连通块大小的乘积.$\text{点数.询问数} \leq 10^5$ 图上连边,$LCT$跑不掉 支持子树$size$有点麻烦.我们需要虚子树的$size$和(实子树的可以直接$pushup$),那么我们对于每一个点就去维护其虚子树的$size$和,那么每一个点的子树和就是可以维护的了.可以知道只有$link$和$access$操作会修改虚子树和(其他都在实链上进行操作),稍微加一点东西就行了.相对来说还是比较裸. 注意

[BJOI2014]大融合 LCT维护子树信息

Code: #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; void setIO(string a){freopen((a+".in").c_str(),"r",stdin);} #define maxn 100009 #define ll long long int n,q

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

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

洛谷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

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

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

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

Loj 2230. 「BJOI2014」大融合 (LCT 维护子树信息)

链接:https://loj.ac/problem/2230 思路: 设立siz数组保存虚点信息,sum表示总信息 维护子树信息link操作和access操作需要进行一些改动 可参考博客:https://www.cnblogs.com/GXZlegend/p/7061458.html 实现代码; #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include&l