/**//* 神奇! 题意:给出一棵树,再给出M条新边,问删除一条树边以及一条新边,使之至少变为两部分的方案数
对于新边(a,b),会在a->LCA(a,b)->b这里形成一个环,所以删除新边(a,b)以及这个环上的没有被其他环覆盖的边 即可分成两部分。所以问题转化为求每条边被环覆盖的次数 设dp[x]表示x所在的父边被覆盖的次数 引进一条新边(a,b)后,dp[a]++,dp[b]++ 而这个环上的其他边的统计可以用treeDP解决,即for(v) dp[u]+=dp[v] 注意到LCA(a,b)的父边是不在环上的,所以每次引进新边(a,b),dp[LCA[a,b]]-=2 最后,if(dp[i]==1)ans++ 删除该边及覆盖它的那个环 if(dp[i]==0)ans+=M 表明这条树边是桥,删除它及任意一条新边都可以
不明白为什么跟别人的差了300多ms 跟3694有一点点类似,新加入的边都是在a->LCA(a,b)->b形成环 */ #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std;
const int MAXN = 100005;
struct Node { int v,next; }nodes[2*MAXN];
int N,M,alloc,done; int G[MAXN],dp[MAXN]; int F[2*MAXN],B[2*MAXN],pos[MAXN]; int rmq[MAXN*2][20];
void add(int a,int b) { nodes[++alloc].v=b,nodes[alloc].next=G[a]; G[a]=alloc; } void dfs(int u,int p,int dep) { F[++done]=u,B[done]=dep; pos[u]=done; for(int son=G[u];son;son=nodes[son].next){ int v=nodes[son].v; if(v==p)continue; dfs(v,u,dep+1); F[++done]=u,B[done]=dep; } } void initRMQ() { for(int i=1;i<=done;i++)rmq[i][0]=i; for(int j=1;(1<<j)<=done;j++) for(int i=1;i+(1<<j)-1<=done;i++) if(B[rmq[i][j-1]]<B[rmq[i+(1<<(j-1))][j-1]])rmq[i][j]=rmq[i][j-1]; else rmq[i][j]=rmq[i+(1<<(j-1))][j-1]; } int LCA(int a,int b) { a=pos[a],b=pos[b]; if(a>b)swap(a,b); int k=log(1.0+b-a)/log(2.0); if(B[rmq[a][k]]<B[rmq[b-(1<<k)+1][k]])return F[rmq[a][k]]; else return F[rmq[b-(1<<k)+1][k]]; } void treeDP(int u,int p) { for(int son=G[u];son;son=nodes[son].next){ int v=nodes[son].v; if(v==p)continue; treeDP(v,u); dp[u]+=dp[v]; } } int main() { while(~scanf("%d%d",&N,&M)){ memset(G+1,0,sizeof(int)*N); memset(dp+1,0,sizeof(int)*N); done = alloc = 0; int a,b; for(int i=1;i<N;i++){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1,1,0); initRMQ(); for(int i=1;i<=M;i++){ scanf("%d%d",&a,&b); dp[a]++,dp[b]++; dp[LCA(a,b)]-=2; } treeDP(1,1); int ans=0; for(int i=2;i<=N;i++){ if(dp[i]==0)ans+=M; if(dp[i]==1)ans++; } printf("%d\n",ans); } return 0; }
/**//* 参考ST版的 不过这个会快点 */ #include<cstdio> #include<cstring>
const int MAXN = 100005;//神奇,改为100010就wa.
struct Node { int v,w,next; }nodes[4*MAXN];
int dp[MAXN],G[MAXN],Q[MAXN]; int fa[MAXN],ans[MAXN]; int N,M,alloc; bool vi[MAXN];
void add1(int a,int b) { alloc++; nodes[alloc].v=b,nodes[alloc].next=G[a]; G[a]=alloc; } void add2(int a,int b,int c) { alloc++; nodes[alloc].v=b,nodes[alloc].w=c; nodes[alloc].next=Q[a]; Q[a]=alloc; } int find(int a) { if(fa[a]==a)return a; return fa[a]=find(fa[a]); }
void Tarjan(int u) { vi[u]=1; for(int son=Q[u];son;son=nodes[son].next){ int v=nodes[son].v,id=nodes[son].w; if(vi[v])ans[id]=find(v); } for(int son=G[u];son;son=nodes[son].next){ int v=nodes[son].v; if(!vi[v]){ Tarjan(v); fa[v]=u; } } } void treeDP(int u,int p) { for(int son=G[u];son;son=nodes[son].next){ int v=nodes[son].v; if(v==p)continue; treeDP(v,u); dp[u]+=dp[v]; } }
int main() { while(~scanf("%d%d",&N,&M)){ memset(G+1,0,sizeof(int)*N); memset(Q+1,0,sizeof(int)*N); memset(dp+1,0,sizeof(int)*N); memset(vi+1,0,sizeof(int)*N); alloc=0; int a,b; for(int i=1;i<=N;i++)fa[i]=i; for(int i=1;i<N;i++){ scanf("%d%d",&a,&b); add1(a,b); add1(b,a); } for(int i=1;i<=M;i++){ scanf("%d%d",&a,&b); add2(a,b,i); add2(b,a,i); dp[a]++; dp[b]++; } Tarjan(1); for(int i=1;i<=M;i++) dp[ans[i]]-=2; treeDP(1,1); int ans=0; for(int i=2;i<=N;i++){ if(dp[i]==0)ans+=M; if(dp[i]==1)ans++; } printf("%d\n",ans); } return 0; }
|