zoukankan      html  css  js  c++  java
  • BZOJ4530:[BJOI2014]大融合(LCT)

    Description

    小强要在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)。
    现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
    询问。

    Input

    第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
    接下来的Q行,每行是如下两种格式之一:
    A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
    Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
    1≤N,Q≤100000

    Output

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

    Sample Input

    8 6
    A 2 3
    A 3 4
    A 3 8
    A 8 7
    A 6 5
    Q 3 8

    Sample Output

    6

    Solution

    一个讲lct维护子树讲的很好的blog
    感觉很好理解,就是$pushup$的时候把虚树的也合并一下
    就是很鸡肋,因为这样就不能维护边了
    $Size$表示子树的全部信息,$Si$表示虚子树的信息
    询问的时候就是边两个端点的子树和的乘积
    此题$link$的时候要将$y~makeroot$不然信息就会错误(在这挂了好久

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (100000+100)
     5 using namespace std;
     6 
     7 int Father[N],Son[N][2],Size[N],Si[N],Rev[N];
     8 int n,m,x,y;
     9 char opt[10];
    10 
    11 int  Get(int x) {return Son[Father[x]][1]==x;}
    12 void Update(int x) {Size[x]=Si[x]+Size[Son[x][0]]+Size[Son[x][1]]+1;}
    13 int  Is_root(int x) {return Son[Father[x]][0]!=x && Son[Father[x]][1]!=x;}
    14 
    15 void Rotate(int x)
    16 {
    17     int wh=Get(x);
    18     int fa=Father[x],fafa=Father[fa];
    19     if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
    20     Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
    21     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
    22     Father[x]=fafa; Son[x][wh^1]=fa;
    23     Update(fa); Update(x);
    24 }
    25 
    26 void Pushdown(int x)
    27 {
    28     if (Rev[x] && x)
    29     {
    30         if (Son[x][0]) Rev[Son[x][0]]^=1;
    31         if (Son[x][1]) Rev[Son[x][1]]^=1;
    32         swap(Son[x][0],Son[x][1]);
    33         Rev[x]=0;
    34     }
    35 }
    36 
    37 void Push(int x) {if (!Is_root(x)) Push(Father[x]); Pushdown(x);}
    38 void Splay(int x)
    39 {
    40     for (int fa;!Is_root(x);Rotate(x))
    41         if (!Is_root(fa=Father[x]))
    42             Rotate(Get(fa)==Get(x)?fa:x);
    43 }
    44 
    45 void Access(int x) {for (int y=0;x;y=x,x=Father[x]) Splay(x), Si[x]+=Size[Son[x][1]], Si[x]-=Size[y], Son[x][1]=y, Update(x);}
    46 void Make_root(int x) {Access(x); Splay(x); Rev[x]^=1;}
    47 int  Find_root(int x) {Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;}
    48 void Link(int x,int y) {Make_root(x); Make_root(y); Father[x]=y; Si[y]+=Size[x]; Update(y);}
    49 int Query(int x,int y)
    50 {
    51     Make_root(x);
    52     Access(y);
    53     Splay(y);
    54     int sum=Size[y];
    55     int sizex=Size[x];
    56     int sizey=sum-sizex;
    57     return sizex*sizey;
    58 }
    59 
    60 int main()
    61 {
    62     scanf("%d%d",&n,&m);
    63     for(int i=1;i<=n;++i) Size[i]=1;
    64     for (int i=1;i<=m;++i)
    65     {
    66         scanf("%s%d%d",opt,&x,&y);
    67         if (opt[0]=='A') Link(x,y);
    68         else printf("%d
    ",Query(x,y));
    69     }
    70 }
  • 相关阅读:
    Two strings CodeForces
    Dasha and Photos CodeForces
    Largest Beautiful Number CodeForces
    Timetable CodeForces
    Financiers Game CodeForces
    AC日记——整理药名 openjudge 1.7 15
    AC日记——大小写字母互换 openjudge 1.7 14
    AC日记——将字符串中的小写字母换成大写字母 openjudge 1.7 13
    AC日记——加密的病历单 openjudge 1.7 12
    AC日记——潜伏着 openjudge 1.7 11
  • 原文地址:https://www.cnblogs.com/refun/p/8685658.html
Copyright © 2011-2022 走看看