zoukankan      html  css  js  c++  java
  • From Tree to Graph lca 并查集

      题意: 给定一棵树 当前树的答案为 $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
    ",x[1],y[1]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    day 05 讲解java三大特性
    day 02 运算符
    石大 6-9 待提交
    poj分类
    NLog使用总结
    VS 2010下单元测试
    MQTT----物联网常用的消息队列协议
    使用jfreechart生成柱状图、折线图、和饼状图
    JavaBean持久化
    使用maven搭建springMVC开发环境
  • 原文地址:https://www.cnblogs.com/bxd123/p/11618282.html
Copyright © 2011-2022 走看看