当前位置 : 主页 > 手机开发 > ROM >

From Tree to Graph lca 并查集

来源:互联网 收集:自由互联 发布时间:2021-06-10
题意: 给定一棵树 当前树的答案为 $f[1]^f[2]^f[3]^..^f[n]$ f[i]表示去除掉i点 该树的联通块数量 有m次操作 每次将两个点连一条边 然后再输出该树的答案 题目 题解: 显然一开始的时候 答

  题意: 给定一棵树 当前树的答案为 $f[1]^f[2]^f[3]^..^f[n]$     f[i]表示去除掉i点 该树的联通块数量   

  有m次操作  每次将两个点连一条边   然后再输出该树的答案

 

题目

题解: 显然一开始的时候  答案为每个点的答案为其度  所以可以处理好一开始的答案

    如果将两个点连在一起的时候  那么该路径所经过的点(不包括这两个端点) 的答案都会减一   

           但是考虑到有时候会重复更新   可以将每个点转移到他到儿子的边上  显然 他有多少个儿子就可以被减多少次答案   正好匹配上了

    用并查集来维护点的归属  所以每条边只会被遍历一次  那么复杂度就是  均摊了复杂度m

    比赛的时候被lca卡了   写的是树剖lca   其实可以暴力预处理出所有的lca

分享图片
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
int f[N],n,a,b,x[2],y[2],z[2],deg[N],ans,m;
int find1(int x){return f[x]==x?x:f[x]=find1(f[x]);}
int dep[N],fa[N],siz[N],pre[N],id[N],lca[N][N],pos,ncnt,head[N];
struct Edge{int to,nex;}edge[N<<1];
void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
void dfs(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;id[x]=++ncnt;pre[ncnt]=x;siz[x]=1;lca[x][x]=x;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==f)continue;
        dfs(v,x);siz[x]+=siz[v];
        for(int j=id[x];j<id[v];j++)
            for(int k=id[v];k<id[v]+siz[v];k++)
            lca[pre[j]][pre[k]]=lca[pre[k]][pre[j]]=x;
    }
}
void solve(int x,int y)
{
    x=find1(x);
    while(dep[x]>dep[y]+1)
    {
         ans^=deg[fa[x]];
         deg[fa[x]]--;
         ans^=deg[fa[x]];
         f[x]=fa[x];
         x=find1(fa[x]);
    }
}
void init()
{
    for(int i=0;i<=n;i++)f[i]=i,head[i]=0,deg[i]=0;
    ncnt=ans=pos=0;
}
int main()
{
    while(scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&x[0],&y[0])!=EOF)
    {
        int u,v;
        init();
        for(int i=1;i<n;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u),deg[u]++,deg[v]++;
        dfs(0,0);
        for(int i=0;i<n;i++)ans^=deg[i];
        z[0]=ans;
        for(int i=1;i<=m;i++)
        {
            x[1]=(a*x[0]+b*y[0]+z[0])%n;
            y[1]=(b*x[0]+a*y[0]+z[0])%n;
            solve(x[1],lca[x[1]][y[1]]);
            z[0]=ans;x[0]=x[1];y[0]=y[1];
        }
        printf("%d %d\n",x[1],y[1]);
    }
    return 0;
}
View Code
网友评论