【并查集】HDU6334 Problems on a Tree

题意:

给出一颗,树上有三种权值的边。
给出m次修改以及询问

每次修改将某条边的权值-1(1则不变)

定义从 u 能走到 v 的条件是,在从 u v 的路径上,遇到第一条权值为3的边后,之后只有权值为1的边。

询问有2个,首先询问能否从t走到s,其次询问有多少点能走到s


分析:

考场上再次看错题。。。。尼玛是棵树啊!!!!

后来发现错误,想到正解已经是最后30分钟了。。。没调出来GG

其实是树的话就很简单了。

首先,可以存一个点向上,只走权值为1的边能达到的最远点(设为 f 1 ( x ) )。以及只走1或2,能到达的最远点(设为 f 2 ( x ) )。(维护可以用并查集)

设一个点的父亲节点为 f a ( x )

第一问

这样一来,询问的第一问就很简单了,只需要考虑3种情况:
1 f 2 ( s ) = f 2 ( t ) ,说明只经过1或2的边就能走到。
2 f 2 ( f a ( f 1 ( s ) ) ) = f 2 ( t ) ,说明从s向上只走1的边,直到第一个非1的边,再只走1或2的边就能到达t(即包含了经过权值为3的边的情况)
3 f 1 ( s ) = f 1 ( f a ( f 2 ( t ) ) ) ,说明从t向上走权值为1或2的边,直到第一个3的边,再只走1就能到达s(这种情况主要是对s为t的祖先而处理的,相对应的,2情况能处理t是s的祖先的情况,而这个不能。如果s和t没有祖先关系,这种情况其实和2等价)

第二问

然后就是如何维护第二问的答案。

这里又要用到上面两个并查集了。
换一种说法定义这两个并查集,无非就是:只经过1的边形成的联通块( f 1 ( x ) 即为x所在并查集的根),只经过1或2的边形成的联通块( f 2 ( x ) 即为x所在并查集的根)。

考虑所有能到达s的点需要满足的条件:必须是从s出发,只经过1的边,直到一条非1的边(可为2可为3)后,只经过1或2的边能到达的点。

那么就可以把答案分为2部分,一部分是只经过1或2的边能达到的点数,一部分先经过1的边再经过一条3的边能到达的点数。

(其实说是这样说,但实现的时候却是两部分混在一起求的)

首先两个并查集分别维护一个值,第一个并查集(只有1的边)维护从它向下走,遇到第一个3的边后,只经过1或2的边能到达的点的个数(定义为 s i z 1 ( f 1 ( x ) ) )。
第二个并查集(有1或2的边)维护它的集合大小(定义为 s i z 2 ( f 2 ( x ) ) )。

这样一来,询问时,首先加上 s i z 2 ( f 2 ( x ) )

然后判断其向上第一条非1的边是否为3,如果是3,则加上经过那条边后到达的点 y s i z 2 ( f 2 ( y ) ) (这里其实是第二部分的答案,但因为不方便维护祖先的信息,所以在查询的时候求)。

然后再加上 s i z 1 ( f 1 ( x ) ) 即可。

连边(更新)的时候,设两个点分别为 x , y ( x y )
如果是2的边(从3变为2的边),
s i z 1 ( f 1 ( x ) ) 减去 s i z 2 ( y ) , s i z 1 ( f 1 ( f a ( x ) ) ) 加上 s i z 2 ( y ) ,即表示原来(x,y)这条3的边没有了,要更新它能贡献的新的祖先的信息。
如果1的边(从2变为1的边),则直接并查集合并即可。


这里说一下题外话。我看了标程的实现。。发现有一堆用不着的东西。。。看来这标程的作者自己也没想清楚啊。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define y1 We_can_read_of_things_that_happened_5,000_years_ago_in_the_Near_East,_where_people_first_learned_to_write._But_there_are_some_parts_of_the_word_where_even_now_people_cannot_write._The_only_way_that_they_can_preserve_their_history_is_to_recount_it_as_sagas_--_legends_handed_down_from_one_generation_of_another._These_legends_are_useful_because_they_can_tell_us_something_about_migrations_of_people_who_lived_long_ago,_but_none_could_write_down_what_they_did._Anthropologists_wondered_where_the_remote_ancestors_of_the_Polynesian_peoples_now_living_in_the_Pacific_Islands_came_from._The_sagas_of_these_people_explain_that_some_of_them_came_from_Indonesia_about_2,000_years_ago.
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
int fa[MAXN],f1[MAXN],f2[MAXN],dep[MAXN];
int siz[MAXN],siz2[MAXN];
vector<int> a[MAXN],w[MAXN];
int get_fa1(int x){
    if(!f1[x])
        return x;
    f1[x]=get_fa1(f1[x]);
    return f1[x];
}
int get_fa2(int x){
    if(!f2[x])
        return x;
    f2[x]=get_fa2(f2[x]);
    return f2[x];   
}
void union1(int x,int y){
    if(dep[x]>dep[y])
        swap(x,y);
    x=get_fa1(x);
    y=get_fa1(y);
    f1[y]=x;
    siz[x]+=siz[y];
}
void union2(int x,int y){
    if(dep[x]>dep[y])
        swap(x,y);
    x=get_fa2(x);
    y=get_fa2(y);
    f2[y]=x;
    siz2[x]+=siz2[y];
    siz[get_fa1(fa[y])-=siz2[y];
    int xx=get_fa1(fa[x]);
    //PF("{%d %d %d %d %d}\n",x,y,xx,siz[x],siz[y]);
    if(xx)
        siz[xx]+=siz2[y];
}
void dfs(int x,int fax){
    dep[x]=dep[fax]+1;
    fa[x]=fax;
    for(int i=0;i<a[x].size();i++){
        if(a[x][i]==fax)
            continue;
        siz[x]++;
        dfs(a[x][i],x); 
    }
    for(int i=0;i<a[x].size();i++){
        if(a[x][i]==fax)
            continue;
        if(w[x][i]==2)
            union2(x,a[x][i]);
        if(w[x][i]==1){
            union2(x,a[x][i]);
            union1(x,a[x][i]);
        }
    }
}
void update(int x,int y){
    x=get_fa1(x);
    y=get_fa1(y);
    if(get_fa1(x)!=get_fa1(y)){
        //if(dep[x]<dep[y])
        //  swap(x,y);
        if(get_fa2(x)==get_fa2(y))
            union1(x,y);
        else
            union2(x,y);
    }
}
int n,m,u,v,s,t,val;
int main(){
    int T;
    SF("%d",&T);
    while(T--){
        SF("%d%d",&n,&m);   
        for(int i=1;i<=n;i++)
            siz2[i]=1;
        for(int i=1;i<n;i++){
            SF("%d%d%d",&u,&v,&val);
            a[u].push_back(v);
            a[v].push_back(u);
            w[u].push_back(val);
            w[v].push_back(val);    
        }
        dfs(1,0);
        for(int i=1;i<=m;i++){
            SF("%d%d%d%d",&u,&v,&s,&t); 
            bool flag=0;
            update(u,v);
            if(get_fa2(s)==get_fa2(t)||get_fa1(fa[get_fa2(t)])==get_fa1(s)||get_fa2(fa[get_fa1(s)])==get_fa2(t))
                flag=1;
            //PF("{%d %d}\n",get_fa1(s),siz[get_fa1(s)]);
            int ans=siz2[get_fa2(s)]+siz[get_fa1(s)];
            if(get_fa2(s)!=get_fa2(fa[get_fa1(s)]))//val = 3
                ans+=siz2[get_fa2(fa[get_fa1(s)])];
            PF("%d %d\n",flag,ans);
        }
        for(int i=1;i<=n;i++){
            f2[i]=0;
            f1[i]=0;    
            siz[i]=0;
            a[i].clear();
            w[i].clear();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/81355457