• [lct] Luogu P4219 大融合


    题目描述

    小强要在NN个孤立的星球上建立起一套通信系统。这套通信系统就是连接NN个点的一个树。 这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它的简单路径的数量。

    例如,在上图中,现在一共有了55条边。其中,(3,8)(3,8)这条边的负载是66,因 为有六条简单路径2-3-8238,2-3-8-72387,3-8,3-8-738,387,4-3-8438,4-3-8-74387路过了(3,8)(3,8)。

    现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的 询问。

    输入输出格式

    输入格式:

    第一行包含两个整数 N, QN,Q,表示星球的数量和操作的数量。星球从 11 开始编号。

    接下来的 QQ 行,每行是如下两种格式之一:

    • A x y 表示在 xx和 yy 之间连一条边。保证之前 xx 和 yy是不联通的。
    • Q x y表示询问 (x,y)(x,y) 这条边上的负载。保证 xx 和 yy 之间有一条边。

    输出格式:

    对每个查询操作,输出被查询的边的负载。

    输入输出样例

    输入样例#1:
    8 6
    A 2 3
    A 3 4
    A 3 8
    A 8 7
    A 6 5
    Q 3 8
    输出样例#1:
    6

    说明

    对于所有数据,1≤N,Q≤10^51N,Q105

    题解

    • 对于lct一般都是维护链上的操作,那么怎么维护子树上的信息呢
    • 定义siz[x]表示x的所有虚儿子的子树大小和,size[x]表示x的所有虚儿子+实儿子+自己的子树大小和
    • 那么只要在虚实边变化的时候维护一下siz的大小,同时维护size就好了
    • 求x的子树大小,只要access(x),然后siz[x]+1就是答案了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #define N 300010
     5 using namespace std;
     6 int n,m,f[N],ch[N][2],v[N],s[N],size[N],tag[N];
     7 int nroot(int x) { return ch[f[x]][0]==x||ch[f[x]][1]==x; }
     8 void pushup(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+s[x]+1; }
     9 void pushdown(int x) { if (tag[x]) swap(ch[x][0],ch[x][1]),tag[ch[x][0]]^=1,tag[ch[x][1]]^=1,tag[x]=0; }
    10 void work(int x) { if (nroot(x)) work(f[x]); pushdown(x); }
    11 void rotate(int x)
    12 {
    13     int y=f[x],z=f[y],k=ch[y][1]==x,w=ch[x][!k];
    14     if (nroot(y)) ch[z][ch[z][1]==y]=x;
    15     ch[x][!k]=y,ch[y][k]=w,f[y]=x,f[x]=z;
    16     if (w) f[w]=y;
    17     pushup(y);
    18 }
    19 void splay(int x) { work(x); while (nroot(x)) rotate(x); pushup(x); }
    20 void access(int x) { for (int y=0;x;x=f[y=x]) splay(x),s[x]+=size[ch[x][1]],s[x]-=size[ch[x][1]=y],pushup(x); }
    21 void makeroot(int x) { access(x),splay(x),tag[x]^=1; }
    22 void split(int x,int y) { makeroot(x),access(y),splay(y); }
    23 void link(int x,int y) { split(x,y);s[f[x]=y]+=size[x],pushup(y); }
    24 int main()
    25 {
    26     scanf("%d%d",&n,&m);
    27     for (int i=1;i<=n;i++) size[i]=i;
    28     for (int x,y;m;m--)
    29     {
    30         char ch=getchar(); while (ch!='A'&&ch!='Q') ch=getchar();
    31         scanf("%d%d",&x,&y);
    32         if (ch=='Q') split(x,y),printf("%lld
    ",(s[x]+1)*(s[y]+1)); else link(x,y);
    33     }
    34 }
  • 相关阅读:
    设计模式二(建造者、原型、桥接)
    MSSQL根据表名动态分页的存储过程以及C#.net调用使用
    查询身份证号码信息(C#.NET)
    初试三层+抽象工厂代码生成器
    NET多线程与异步编程
    【SQL.SERVER.DMVS.实战】学习笔记
    【SQL.SERVER.DMVS.实战】学习笔记(二)
    SQL Server 2005数据文件数据的存储
    ASP.NET第九天加强课程
    ASP.NET第四天加强课程
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11129335.html
Copyright © 2020-2023  润新知