• 【BZOJ-4530】大融合 线段树合并


    4530: [Bjoi2014]大融合

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 280  Solved: 167
    [Submit][Status][Discuss]

    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

    HINT

    Source

    鸣谢佚名上传

    Solution

    这题的思路还是很好的,自己思考了一段时间才能想出来。

    对于一次询问$<u,v>$,答案显然就是$size[u]*size[v]$,但是需要维护这样的树的形态并且询问。

    然后我想了一种线段树合并的方法,但是蛋疼的地方是询问时的$size$很鸡肋,不能直接询问。

    因为合并时是合并到一个点上,其余的点的线段树形态并不完整,这个地方其实和并查集很类似,那么再用并查集维护一下每个块的代表元素即可。

    这样查询另一个点时也会有问题,那么限定查询区间为dfs序两端即可,然后这个题就很简单了,然后这个问题就转化成了$(size[root]-size[u])*size[u]$。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
     
    #define MAXN 200010
     
    int N,Q;
     
    struct EdgeNode{
        int next,to;
    }edge[MAXN];
    int head[MAXN],cnt=1;
    inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
     
    int fa[MAXN];
    inline int F(int x) {if (fa[x]==x) return x; else return fa[x]=F(fa[x]);}
     
    struct SgtNode{
        int lson,rson,size;
    }tree[MAXN*20];
    int root[MAXN],sz;
     
    inline void Update(int x) {tree[x].size=tree[tree[x].lson].size+tree[tree[x].rson].size;}
     
    inline int Merge(int x,int y)
    {
        if (!x || !y) return x|y;
        tree[x].size+=tree[y].size;
        tree[x].lson=Merge(tree[x].lson,tree[y].lson);
        tree[x].rson=Merge(tree[x].rson,tree[y].rson);
        return x;
    }
     
    inline void Insert(int &x,int l,int r,int pos)
    {
        x=++sz;
        if (l==r) {
            tree[x].size=1;
            return;
        }
        int mid=(l+r)>>1;
        if (pos<=mid) Insert(tree[x].lson,l,mid,pos);
            else Insert(tree[x].rson,mid+1,r,pos);
        Update(x);
    }
     
    inline int Query(int x,int l,int r,int L,int R)
    {
    	if (!x) return 0;
        if (L<=l && R>=r) return tree[x].size;
        int mid=(l+r)>>1,re=0;
        if (L<=mid) re+=Query(tree[x].lson,l,mid,L,R);
        if (R>mid) re+=Query(tree[x].rson,mid+1,r,L,R);
        return re;
    }
     
    int pl[MAXN],pre[MAXN],pr[MAXN],dfn,deep[MAXN];
    inline  void DFS(int now,int last)
    {
        pl[now]=++dfn; pre[dfn]=now;
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=last)
                deep[edge[i].to]=deep[now]+1,
                DFS(edge[i].to,now);
        pr[now]=dfn;
    }
     
    struct QNode{
        int opt,x,y;
    }Qr[MAXN];
     
    int main()
    {
        N=read(),Q=read();
         
        for (int i=1; i<=Q; i++) {
            char opt[5]; scanf("%s",opt+1);
            int x=read(),y=read();
            if (opt[1]=='A') InsertEdge(x,y);
            Qr[i]=(QNode){(opt[1]=='A'? 0:1),x,y};
        }
     
        for (int i=1; i<=N; i++) if (!deep[i]) DFS(i,0);
         
        for (int i=1; i<=N; i++) fa[i]=i,Insert(root[i],1,N,pl[i]);
        
        for (int i=1; i<=Q; i++) {
            if (Qr[i].opt==0) {
                int x=F(Qr[i].x),y=F(Qr[i].y);
                if (deep[x]>deep[y]) swap(x,y);
                root[x]=Merge(root[x],root[y]);
                fa[y]=x;
            } else {
                int x=Qr[i].x,y=Qr[i].y,z;
                if (deep[x]<deep[y]) swap(x,y); z=F(x);
                int siz=Query(root[z],1,N,pl[x],pr[x]);
                printf("%lld
    ",1LL*(tree[root[z]].size-siz)*siz);
            }
        }
        
        return 0;
    }
    

      

  • 相关阅读:
    深入理解 ProtoBuf 原理与工程实践(概述)
    高性能缓存 Caffeine 原理及实战
    Java 多线程上下文传递在复杂场景下的实践
    SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
    MySQL 5.6.35 索引优化导致的死锁案例解析
    gitlab安装升级(大版本跨度9.4.5----13.2.1)
    mysql 查看表的索引
    python安装mysql库 ,MySQL-python
    Alpine包管理工具apk使用介绍
    docker容器添加hosts
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6581079.html
Copyright © 2020-2023  润新知