zoukankan      html  css  js  c++  java
  • 【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;
    }
    

      

  • 相关阅读:
    enter事件处方方法
    vue 关于父组件无法触发子组件的事件的解决方法
    iview表格高度自适应只需要三步即可
    子组件触发父组件的方法
    组件之间的方法
    年与日时分秒各种格式 补0位的方法
    //定义一个函数,删除首个数组元素
    input标签内容改变的触发事件
    jQuery表单校验jquery.validate.js的使用
    jQuery BlockUI 实现锁屏
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6581079.html
Copyright © 2011-2022 走看看