3592: 【USACO】锻炼路线
时间限制: 1.000 Sec 内存限制: 256 MB
提交: 6 解决: 2
[命题人:][下载数据: 90]
提交状态报告
题目描述
奶牛Bessie意识到为了保持好的体形她需要更多地进行锻炼。她需要你帮助她选择在农场里每天用来晨跑的路线。
农场由N块草地组成(1≤N≤2⋅105),方便起见编号为1…N,由M条双向的小路连接(1≤M≤2⋅105)。作为一种遵循规律的生物,奶牛们倾向于使用其中特定的N−1条小路作为她们日常在草地之间移动的路线——她们管这些叫“常规的”小路。从每块草地出发都可以仅通过常规的小路到达所有其他草地。
为了使她的晨跑更加有趣,Bessie觉得她应该选择一条包含一些非常规的小路的路线。然而,使用常规的小路能够使她感到舒适,所以她不是很想在她的路线中使用过多非常规的小路。经过一些思考,她认为一条好的路线应当形成一个简单环(能够不经过任何草地超过一次的情况下回到起点),其中包含恰好两条非常规的小路。
请帮助Bessie计算她可以使用的好的路线的数量。两条路线被认为是相同的,如果它们包含的小路的集合相等。
输入
输入的第一行包含N和M。以下M行每行包含两个整数ai和bi,描述了一条小路的两端。其中前N−1条是常规的小路。
输出
输出Bessie可以选择的路线的总数。
样例
输入 复制
5 8 1 2 1 3 1 4 1 5 2 3 3 4 4 5 5 2
输出 复制
4
来源/分类
题解
#include<cstdio> #include<cstdlib> #include<map> #include<algorithm> #define maxn 400005 #define ll long long using namespace std; int pre[maxn],to[maxn],las[maxn],mk[maxn],sum[maxn],inc; int fa[maxn][22],dep[maxn],st[maxn],en[maxn],lca[maxn],n,m; ll ans=0; void ins(int a,int b){pre[++inc]=las[a],las[a]=inc,to[inc]=b;} void GetFa(int x,int f) { dep[x]=dep[f]+1,fa[x][0]=f; for(int i=1;i<=21;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=las[x],y=to[i];i;i=pre[i],y=to[i]) if(y!=f) GetFa(y,x); } void dfs(int x,int f,int now) { sum[x]=(now+=mk[x]); for(int i=las[x],y=to[i];i;i=pre[i],y=to[i]) if(y!=f) dfs(y,x,now); } int LCA(int x,int y) { if(dep[x]<dep[y]) swap(x,y); int delta=dep[x]-dep[y]; for(int i=21;i>=0;i--) if((delta>>i)&1) x=fa[x][i]; if(x==y) return x; for(int i=21;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int Close(int x,int anc) { if(x==anc) return -1; for(int i=21;i>=0;i--) if(fa[x][i]&&dep[fa[x][i]]>dep[anc]) x=fa[x][i]; return x; } map<pair<int,int>,int> mp; int main() { scanf("%d%d",&n,&m); for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),ins(v,u),ins(u,v); GetFa(1,0); for(int i=n;i<=m;i++) { scanf("%d%d",&st[i],&en[i]); lca[i]=LCA(st[i],en[i]); int ux=Close(st[i],lca[i]); int uy=Close(en[i],lca[i]); if(ux!=-1) ans-=(++mk[ux]); if(uy!=-1) ans-=(++mk[uy]); if(ux!=-1&&uy!=-1) { if(ux>uy) swap(ux,uy); ans-=(mp[make_pair(ux,uy)]++); } } dfs(1,0,0); for(int i=n;i<=m;i++) ans+=sum[st[i]]+sum[en[i]]-2*sum[lca[i]]; printf("%lld\n",ans); return 0; }