【HDU5452】Minimum Cut

来源:互联网 发布:51单片机cy和ac 编辑:程序博客网 时间:2024/05/20 10:21

转送门
题目大意:已知一个n节点m条边的无向图以及它所对应的一棵生成树,要求只能删除一条树边和若干条非树边,求最少要删除多少条边。
注意:必须删除一条树边且只能删除一条树边(蒟蒻一开始理解成了至少删除一条树边QAQ)

既然必须删除一条树边,那么就枚举这一条树边吧o(>﹏<)o
删去这条树边之后,生成树就被分成了两个部分,我们只需要将连接这两个部分的边全部删除即可。

那么问题来了,怎样快速滴算出一条树边所对应的非树边呢(⊙o⊙)?
考虑一条非树边所影响的树边。这条边e(u,v),必然是uv之间的树边所对应的非树边。(理解:当这些树边被删除后,uv必定分属于两个不同的部分)
我第一次交的是用树剖直接在边的cnt上加1,一交1860ms。然后我又原封不动滴交了一遍就T了/(ㄒoㄒ)/~~
之后写的是在e(u,v)lca上直接操作,920ms,无压力A掉。

#include <iostream>#include <cstdio>#include <cstring>#define MAXN 100005#define MAXM 830395using namespace std;int pos, adj[MAXN], n, ans[MAXN], a[MAXN];struct node{    int v, next;}edge[MAXN<<1], e[MAXM];void add(int a,int b){    edge[pos].v=b, edge[pos].next=adj[a];    adj[a]=pos;++pos;}int road[MAXN<<1], c, cnt[MAXN];void dfs(int u,int fa){    road[++c]=u;    for(int p=adj[u], v;~p;p=edge[p].next)        if((v=edge[p].v)!=fa)            dfs(v,u);    road[++c]=-u;}int head[MAXN], pos2;void Add(int a,int b){    ++pos2;    e[pos2].v=b, e[pos2].next=head[a];    head[a]=pos2;}bool flag[MAXN];int prime[MAXN], cntp, mo[MAXN];void init(){    mo[1]=1;    for(int i=2;i<=100000;++i)    {        if(!flag[i]){prime[++cntp]=i;mo[i]=-1;}        for(int j=1;j<=cntp&&i*prime[j]<=100000;++j)        {            flag[i*prime[j]]=1;            if(i%prime[j]==0)            {                mo[i*prime[j]]=0;                break;            }            mo[i*prime[j]]=-mo[i];        }    }    memset(head,-1,sizeof head);    for(int i=1;i<=100000;++i)        if(mo[i])            for(int j=i;j<=100000;j+=i)                Add(j,i);}int main(){    init();    int cas=0, u, v;    while(~scanf("%d",&n))    {        memset(cnt,0,sizeof cnt), memset(adj,-1,sizeof adj);        c=pos=0;        for(int i=1;i<n;++i)        {            scanf("%d%d",&u,&v);            add(u,v), add(v,u);        }        for(int i=1;i<=n;++i)scanf("%d",&a[i]);        dfs(1,0);        printf("Case #%d:",++cas);        for(int i=1;i<=n;++i)ans[i]=a[i]==1;        for(int i=1, t;i<=c;++i)        {            t=road[i];            if(t>0)            {                for(int p=head[a[t]], b;~p;p=e[p].next)                {                    b=e[p].v;                    ++cnt[b];                    ans[t]-=mo[b]*cnt[b];                }            }            else            {                t=-t;                for(int p=head[a[t]], b;~p;p=e[p].next)                {                    b=e[p].v;                    ans[t]+=mo[b]*cnt[b];                }            }        }        for(int i=1;i<=n;++i)printf(" %d",ans[i]);        puts("");    }    return 0;}
0 0