Poj 3107 树的重心,前向星

来源:互联网 发布:淘宝网发布禁售信息 编辑:程序博客网 时间:2024/05/10 10:50

今天美团的比赛打得和屎一样,D似乎是一个点分治,但是我TM完全没写过,于是就直接弃赛去学了。在ACdreamer处写了两个重心模板题,第一个很顺利,第二个莫名T了,看了discuss发现卡了我一直用的vector,于是又在ACdreamer这里学了下前向星,把我T的代码xjb改了下就过了,看来这玩意卡常数很管用,之后尽量多用吧。

代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;int n, msiz, tot, cnt;struct Edge{    int to, next;}edge[50500<<1];int head[50500];bool vis[50500];int siz[50500];int rsiz[50500];int ans[50500];void init(){    memset(head, -1, sizeof(head));    cnt=0;}void add(int u, int v){    edge[cnt].to=v;    edge[cnt].next=head[u];    head[u]=cnt++;}void dfs(int u){    vis[u]=true;    siz[u]=1;    int tmp=0;    for(int i=head[u];~i;i=edge[i].next){        int v=edge[i].to;        if(!vis[v]){            dfs(v);            siz[u]+=siz[v];            tmp=max(tmp, siz[v]);        }    }    tmp=max(tmp, n-siz[u]);    if(tmp<msiz){        msiz=tmp;    }    rsiz[u]=tmp;}int main(){    while(~scanf("%d", &n)){        init();        for(int i=1;i<n;i++){            int x, y;            scanf("%d%d", &x, &y);            add(x, y);            add(y, x);        }        memset(vis, false, sizeof(vis));        msiz=n;        dfs(1);        tot=0;        for(int i=1;i<=n;i++)if(rsiz[i]==msiz)ans[++tot]=i;        for(int i=1;i<=tot;i++)printf("%d%c", ans[i], i==tot?'\n':' ');    }}

胡扯一下,之前有遇到要删边(双向)的情况,这个似乎可以搞,但是大概除了next还要记录pre,这样就和双向链表一样方便删除了,而且由于正反向边一般是成对添加,所以反向边很好找到(异或1即可)。
之前CF也挂了个树形依赖背包,正好借这个契机把树上问题好好搞一搞。