![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//*
神奇!
题意:给出一棵树,再给出M条新边,问删除一条树边以及一条新边,使之至少变为两部分的方案数
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
对于新边(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 表明这条树边是桥,删除它及任意一条新边都可以
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
不明白为什么跟别人的差了300多ms
跟3694有一点点类似,新加入的边都是在a->LCA(a,b)->b形成环
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
const int MAXN = 100005;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
struct Node
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
int v,next;
}nodes[2*MAXN];
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
int N,M,alloc,done;
int G[MAXN],dp[MAXN];
int F[2*MAXN],B[2*MAXN],pos[MAXN];
int rmq[MAXN*2][20];
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void add(int a,int b)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
nodes[++alloc].v=b,nodes[alloc].next=G[a];
G[a]=alloc;
}
void dfs(int u,int p,int dep)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
F[++done]=u,B[done]=dep;
pos[u]=done;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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()
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
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)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
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)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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()
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for(int i=1;i<N;i++) {
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs(1,1,0);
initRMQ();
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for(int i=2;i<=N;i++) {
if(dp[i]==0)ans+=M;
if(dp[i]==1)ans++;
}
printf("%d\n",ans);
}
return 0;
}
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//*
参考ST版的
不过这个会快点
*/
#include<cstdio>
#include<cstring>
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
const int MAXN = 100005;//神奇,改为100010就wa .
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
struct Node
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
int v,w,next;
}nodes[4*MAXN];
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
int dp[MAXN],G[MAXN],Q[MAXN];
int fa[MAXN],ans[MAXN];
int N,M,alloc;
bool vi[MAXN];
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void add1(int a,int b)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
alloc++;
nodes[alloc].v=b,nodes[alloc].next=G[a];
G[a]=alloc;
}
void add2(int a,int b,int c)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
alloc++;
nodes[alloc].v=b,nodes[alloc].w=c;
nodes[alloc].next=Q[a];
Q[a]=alloc;
}
int find(int a)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
if(fa[a]==a)return a;
return fa[a]=find(fa[a]);
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void Tarjan(int u)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
vi[u]=1;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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);
}
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for(int son=G[u];son;son=nodes[son].next) {
int v=nodes[son].v;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if(!vi[v]) {
Tarjan(v);
fa[v]=u;
}
}
}
void treeDP(int u,int p)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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];
}
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
int main()
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for(int i=1;i<N;i++) {
scanf("%d%d",&a,&b);
add1(a,b);
add1(b,a);
}
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) 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;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for(int i=2;i<=N;i++) {
if(dp[i]==0)ans+=M;
if(dp[i]==1)ans++;
}
printf("%d\n",ans);
}
return 0;
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
|