题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4912
http://vjudge.net/contest/view.action?cid=52719#problem/B
1.题意:
根节点为1,包含n个节点二叉树,上面有m条指定路径,如果从选出其中若干条,使他们没有公共点,求条数的最大值。
2.题解
(1)首先要了解求LCA的算法,本题使用O(nlogn)的算法,O(n)的Tarjan算法不太理解所以稍后另外介绍。
(2)对于每个询问,按照lca的dep值从大到小排序,贪心即可。
(3)用fa[i][j]表示i节点的第2^j个父节点,用fa[i][j]=fa[fa[i][j-1][j-]可以动态规划出fa数组每一项的值。
(4)每次从lca的dep最小的询问开始,首先查看,这条路径上每一个点是否都未被标记,如果都未被标记就说明和之前标记的路径美欧重复点,就说明找到一个答案了,然后对于路径上所有的点进行标记,保证不会和以后的询问的路径有重复点。
(5)代码里添加了输入输出优化
code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN=111111; struct Edge{ int from,to,next; Edge(){} Edge(int f,int t,int n):from(f),to(t),next(n){} }edge[MAXN*2]; int head[MAXN],tot,fa[MAXN][20],dep[MAXN],q[MAXN],n,m; bool vis[MAXN]; struct Qes{ int u,v,lca; Qes(){} Qes(int _u,int _v,int _fa):u(_u),v(_v),lca(_fa){} bool operator<(const Qes&rhs)const{ return dep[lca]>dep[rhs.lca]; } }qes[MAXN]; void init(){ for(int i=1;i<=n;i++){ head[i]=-1; vis[i]=0; } tot=0; } void add(int f,int t){ edge[tot]=Edge(f,t,head[f]); head[f]=tot++; } void bfs(int root){ int tail=0; q[tail++]=root; fa[root][0]=root;dep[root]=0; for(int i=0;i<tail;i++){ int u=q[i]; for(int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].to; if(v==fa[u][0])continue; fa[v][0]=u;dep[v]=dep[u]+1; q[tail++]=v; } } } int Lca(int x,int y){ if(dep[x]<dep[y]){int t=x;x=y;y=t;} for(int i=19;~i;i--) if((dep[x]-dep[y])&(1<<i))x=fa[x][i]; if(x==y)return x; for(int i=19;~i;i--) if(fa[x][i]!=fa[y][i]){x=fa[x][i],y=fa[y][i];} return fa[x][0]; } bool can(int u,int v,int lca){//if u~lca v~lca connected if(vis[u]||vis[v]||vis[lca]) return false; for(;u!=lca;u=fa[u][0]) if(vis[u]) return false; for(;v!=lca;v=fa[v][0]) if(vis[v]) return false; return true; } void cut(int u,int v,int lca){// cut u~lca v~lca for(;u!=lca;u=fa[u][0]) vis[u]=1; for(;v!=lca;v=fa[v][0]) vis[v]=1; vis[lca]=1; } inline bool get(int &a){ char c=0; a=0; do{ c=getchar(); }while(c!=EOF && (c<'0'||c>'9')); if(c==EOF)return false; while('0'<=c && c<='9'){a=a*10-'0'+c;c=getchar();} return true; } inline void ot(int a){ if(a>9) ot(a/10); putchar(a%10+'0'); } int main() { // freopen("data.in","r",stdin); while(get(n)){ get(m); init(); int u,v; for(int i=1;i<n;i++){ get(u); get(v); add(u,v); add(v,u); } bfs(1); for(int i=0;i<m;i++){ get(u); get(v); qes[i]=Qes(u,v,Lca(u,v)); } sort(qes,qes+m); int ans=0; for(int i=0;i<m;i++){ if(can(qes[i].u,qes[i].v,qes[i].lca)){ cut(qes[i].u,qes[i].v,qes[i].lca); ans++; } } ot(ans); putchar('\n'); } return 0; }