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\n",x[1],y[1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bxd123/p/11618282.html

时间: 2024-08-30 17:33:43

From Tree to Graph lca 并查集的相关文章

Codeforces Round #286 div.1 D 506D D. Mr. Kitayuta&#39;s Colorful Graph【并查集】

题目链接:http://codeforces.com/problemset/problem/506/D 题目大意: 给出n个顶点,m条边,每条边上有一个数字,代表某个颜色.不同数字代表不同的颜色.有很多个询问,每个询问问有多少条纯种颜色的路径使得某两个点联通. 分析: 这个题一看就想用并查集来搞,每种颜色用一个并查集处理.对于输入的每条边,我们只需要将这两个点在这条边的颜色对应的并查集中合并就好了.查询的时候,我们只需要检测这两个点在多少个颜色对应的并查集中是在统一集合中的,那么就有多少条纯种颜

【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

[题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1<=wi<=10^9. [算法]最小生成树+倍增LCA+并查集 [题解]首先求出图的一个最小生成树,则所有边分成树边和非树边. 对于非树边(u,v),假设u和v在最小生成树上的路径的最大边权Max,那么一定满足w(u,v)<=Max /////////////////////////////////////// 原文地址:https://ww

CodeForces 593D Happy Tree Party [LCA+并查集]

题意:给一棵树,每条边有一个权值,给两种操作,第一种是询问y向下整除从a到b的最短路径中每条边的权值后y的值,第二种是改变某条边的权值. 思路:y的最大值为1e18,最多除大于等于2的数不超过60次即可将y变为0,先dfs以任意一点为根建树,记录每个点的深度和它的父结点并将边权转化为点权, 再搞个并查集,将权值为1的点压缩,即使pre[u]=g[u];(u变成u的爸爸). 1 #include<bits/stdc++.h> 2 #define fi first 3 #define se sec

Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

题目链接: Hdu 5458 Stability 题目描述: 给出一个还有环和重边的图G,对图G有两种操作: 1 u v, 删除u与v之间的一天边 (保证这个边一定存在) 2 u v, 查询u到v的路径上有几条桥. 解题思路: 这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点.如果按照顺序来,删边时候求桥就是问题了.所以可以离线处理,然后一边记录答案一边加边缩点. 对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目.查询的时候对于(u, v)

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

BZOJ 3910 火车 LCA+并查集

题目大意 给出一棵树,起点,和要经过的点的序列,已经经过的点就不用去了,剩下的点按照顺序依次去,问要经过多少条边. 思路 链剖大概应该是可以,不过没试,用了听大爷说的一种神奇的方法. 因为树上经过的点肯定是一段一段的,就想到用并查集将一段合成一个点,每个点最多只能被合一次,这样的话就能保证时间复杂度.查询的时候像链剖一样一段一段往上跳就行了,还要顺便把路径上的所有点缩起来. CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #incl

【BZOJ-3910】火车 倍增LCA + 并查集

3910: 火车 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 262  Solved: 90[Submit][Status][Discuss] Description A 国有n 个城市,城市之间有一些双向道路相连,并且城市两两之间有唯一路径.现在有火车在城市 a,需要经过m 个城市.火车按照以下规则行驶:每次行驶到还没有经过的城市中在 m 个城市中最靠前的.现在小 A 想知道火车经过这m 个城市后所经过的道路数量. Input 第一行三个整数

【BZOJ3910】火车 LCA+并查集

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44780959"); } 题解: 首先找两点之间路径可以用倍增LCA. 然后标记哪个点走过可以用并查集,均摊下来最后是线性的. 代码: #include <cstdio> #include <cstring>

HDU 4297--One and One Story(LCA&amp;并查集)

One and One Story Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others)Total Submission(s): 1049 Accepted Submission(s): 459 Problem Description Have you ever played the romantic Flash game, "One and One Story"?1 In