CF650 E
来源:互联网 发布:c语言中int什么意思 编辑:程序博客网 时间:2024/06/01 09:22
题意:
给出两棵树,要求将第一棵变成第二棵。可以进行的操作是删除一条边,再加入一条边。要求每次操作后仍是一棵树。问最小操作次数和方案。
n<=500000
#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#include<vector>#define N 510000#define pb push_backusing namespace std;struct node{int y,rx,ry,nex;}a[2*N];vector<int> v1[N],v2[N];int n,fir[N],len,fa[N],fr[N][2],rt,A[N][4],num;bool b[N];void ins(int x,int y,int rx,int ry){ a[++len].y=y;a[len].rx=rx;a[len].ry=ry;a[len].nex=fir[x];fir[x]=len;}int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}void merge(int x,int y){ fa[find(x)]=find(y);}void dfs(int x,int fa){ for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; if(y==fa) continue; fr[y][0]=a[k].rx;fr[y][1]=a[k].ry; dfs(y,x); }}void dfs1(int x,int fa){ for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; if(y==fa) continue; A[++num][0]=fr[y][0];A[num][1]=fr[y][1];A[num][2]=a[k].rx;A[num][3]=a[k].ry; dfs1(y,x); }}int main(){ scanf("%d",&n); for(int i=1;i<n;i++) { int x,y;scanf("%d%d",&x,&y); v1[x].pb(y);v1[y].pb(x); } for(int i=1;i<n;i++) { int x,y;scanf("%d%d",&x,&y); v2[x].pb(y);v2[y].pb(x); } for(int i=1;i<=n;i++) fa[i]=i; for(int x=1;x<=n;x++) { int s1=v1[x].size(),s2=v2[x].size(); for(int j=0;j<s1;j++) b[v1[x][j]]=1; for(int j=0;j<s2;j++) if(b[v2[x][j]]) merge(x,v2[x][j]); for(int j=0;j<s1;j++) b[v1[x][j]]=0; } for(int x=1;x<=n;x++) { int siz=v1[x].size(); for(int j=0;j<siz;j++) { int y=v1[x][j]; if(find(x)!=find(y)) ins(fa[x],fa[y],x,y); } } rt=fa[1]; dfs(rt,0); len=0; for(int i=1;i<=n;i++) fir[i]=0; for(int x=1;x<=n;x++) { int siz=v2[x].size(); for(int j=0;j<siz;j++) { int y=v2[x][j]; if(find(x)!=find(y)) ins(fa[x],fa[y],x,y); } } dfs1(rt,0); printf("%d\n",num); for(int i=1;i<=num;i++) printf("%d %d %d %d\n",A[i][0],A[i][1],A[i][2],A[i][3]);}
题解:
先把对的边缩起来,然后以1为根建出两棵树,这个时候所有边都是错的了。
假设现在有n个点,显然答案下界是n-1。
考虑这样构造:
维护两个集合A,B。初始A为{1},B为{2…n}。
A,B时刻满足如下性质
1、A中的点之间的边是对的
2、只考虑A中的边,A内部是联通的
3、B中的点直接联通,或通过与A有关的边间接联通
4、整个图是一棵树
假设向A中加入一个新点x,这个点和已在A中的y在第二棵树中有边。
此时需要删除x的一条边,然后加入(x,y)。
我们在第一棵树上把A中的点标为红色
那么容易发现,删除第一棵树上x到父亲的边一定正确。
这样,就构造出了答案的下界。
于是模拟即可。
0 0
- CF650 E
- e
- E
- E
- e
- e
- e
- e
- e
- E
- e
- E
- e
- e
- E
- e
- e
- e
- iframe获取父页面的元素
- linux下安装apktool和一些问题解决方案
- 进程-进程之进程状态(R、S、D、T、Z、X)
- arm汇编指令理解
- WINCE下显示文字
- CF650 E
- Linux学习第二单元-控制对文件的访问
- Application对象所存储的 数据如何清空
- Java 8的新特性
- Java中的private、protected、public和default的区别
- web.xml is missing and <failOnMissingWebXml> is set to true
- Android Dialog
- Java NIO
- linq partition by