下午打了湘潭邀请赛,好像缓解了一下北京网络赛超强的自闭感。补一下这个图论题。(补了很久)
题意:给你一颗n节点的树,有m个操作,每次向xi和lca(xi,yi)连边,然后每次zi就是对于新的图在删除每一个点后连通块个数的异或和。然后求的是m次操作后x,y的值。
题解:看这个问题看了好久我都完全无从下手,题意也理解了半天,只知道有环prprpr,然后和x到lca这条链上的点有关系。但是感觉怎么都会T,就只能暴力更新。然后就看别人的题解,并且打开了画图软件,首先,对于一颗树每个点删除后产生的联通块个数就是它的入度和出度的和。然后异或一下就好。也就是和它度数有关。然后对于每次加的那条边,可以发现这条边的两个点的删除后个数不变,而那条链上的其余点联通块个数减减。然后就是最关键的,对于每条边,最多只会更新一次,因为成环后,新加的边所形成的新环,如果更新的链也通过之前存在的环走过的链,此时对于这条链上的点是无影响的,因为原来的这条边已经被减减过了。画图是这样,写博客中间又仔细想了一想,应该是这样理解的?也就是我们可以跳过这些环,缩环为点,用并查集缩环???第一次听说,然后写法上挺有讲究的吧,它可能并查集跳到的点会超过lca,所以要用深度判断一下。如果写的不完全对,以后懂了来改好了
#include<bits/stdc++.h> #define ll long long #define pb push_back #define _mp make_pair #define ldb long double using namespace std; const int maxn=5005; inline ll read() { ll 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; } int lca[maxn][20]; int bcg[maxn],depth[maxn]; int n,m,a,b,x,y; int fir[maxn],nxt[maxn*2],to[maxn*2]; int du[maxn]; int cnt; int ans; void add_e(int x,int y) { ++cnt;nxt[cnt]=fir[x];fir[x]=cnt;to[cnt]=y; ++cnt;nxt[cnt]=fir[y];fir[y]=cnt;to[cnt]=x; } int findd(int x) { return bcg[x]==x?bcg[x]:bcg[x]=findd(bcg[x]); } int LCA(int x,int y) { if(depth[x]<depth[y])swap(x,y); int dd=depth[x]-depth[y]; for(int i=18;i>=0;i--) { if(dd&(1<<i))x=lca[x][i]; } if(x==y)return y; for(int i=18;i>=0;i--) { if(lca[x][i]!=lca[y][i]) { x=lca[x][i]; y=lca[y][i]; } } return lca[x][0]; } void dfs(int x,int fa) { lca[x][0]=fa; depth[x]=depth[fa]+1; for(int i=fir[x];i;i=nxt[i]) { int pp=to[i]; if(pp==fa)continue; dfs(pp,x); } } void lca_init() { dfs(1,0); depth[0]=0; for(int k=1;k<=18;k++) { for(int i=1;i<=n;i++) { lca[i][k]=lca[lca[i][k-1]][k-1]; } } } void init() { memset(depth,0,sizeof(depth)); memset(lca,0,sizeof(lca)); for(int i=1;i<=n;i++)bcg[i]=i; for(int i=1;i<=n;i++)du[i]=0; cnt=0; memset(fir,0,sizeof(fir)); } void update(int x,int y) { x=findd(x); if(depth[lca[x][0]]<=depth[y]||lca[x][0]==0) { return ; } ans=ans^du[lca[x][0]]^(--du[lca[x][0]]); bcg[x]=lca[x][0]; update(lca[x][0],y); } int main() { while(~scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&x,&y)) { init(); int p,q; for(int i=1;i<n;i++) { scanf("%d%d",&p,&q); p++,q++; add_e(p,q); du[p]++,du[q]++; } lca_init(); ans=0; for(int i=1;i<=n;i++) { ans^=du[i]; } for(int i=0;i<m;i++) { int nx=(a*x+b*y+ans)%n; int ny=(b*x+a*y+ans)%n; x=nx; y=ny; update(x+1,LCA(x+1,y+1)); } printf("%d %d ",x,y); } }