【树形DP】 HDU 4008 Parent and son

原题直通车:HDU 4008 Parent and son

分析:

     如果a、b之间存在一条边,那么把a当树根和把b当树根只在a, b这两结点的信息有所区别,其它的不变。

     所以,先以任意一个点做为根的所求出每个点的最小孩子min_son、最小子孙min_des

     然后,就可分别把树根转移到其它结点时,每个点的最小孩子、最小子孙求出。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn=100005;
vector<int>G[maxn];
vector< pair<int,int> >Q[maxn];

int min_son[maxn], min_des[maxn];
int ans1[maxn], ans2[maxn];
bool vis[maxn];
void dfs(int cnt) {
    min_son[cnt]=maxn, min_des[cnt]=maxn;
    vis[cnt]=true;
    int len=G[cnt].size();
    for(int i=0; i<len; ++i) {
        int son=G[cnt][i];
        if(!vis[son]) {
            dfs(son);
            min_son[cnt]=min(min_son[cnt], son);
            min_des[cnt]=min(min_des[cnt], min_des[son]);
        }
    }
    min_des[cnt]=min(min_des[cnt], min_son[cnt]);
}
int Min_son(int cnt, int exp) { //除exp外
    int len=G[cnt].size(), ret=maxn;
    for(int i=0; i<len; ++i)
        if(G[cnt][i]!=exp) ret=min(ret, G[cnt][i]);
    return ret;
}
int Min_des(int cnt, int exp) {  //除exp外
    int len=G[cnt].size(), ret=maxn;
    for(int i=0; i<len; ++i)
        if(G[cnt][i]!=exp) ret=min(ret, min(G[cnt][i],min_des[G[cnt][i]]));
    return ret;
}
void dfs_ans(int cnt) { //cout<<cnt<<endl;
    vis[cnt]=true;
    int len=Q[cnt].size();
    for(int i=0; i<len; ++i) {
        int y=Q[cnt][i].first, k=Q[cnt][i].second;
        ans1[k]=min_son[y], ans2[k]=min_des[y];
    }
    len=G[cnt].size();
    for(int i=0; i<len; ++i) {
        int son=G[cnt][i];
        if(!vis[son]) {
            int cnt_min_son=min_son[cnt], son_min_son=min_son[son];
            int cnt_min_des=min_des[cnt], son_min_des=min_des[son];

            if(son==min_son[cnt])
                min_son[cnt]=Min_son(cnt, son);
            min_son[son]=min(min_son[son], cnt);
            if(son==min_des[cnt]||min_des[son]==min_des[cnt])
                min_des[cnt]=Min_des(cnt, son);
            min_des[son]=min(min_des[son], min(min_des[cnt],cnt));

            dfs_ans(son);

            min_son[cnt]=cnt_min_son, min_son[son]=son_min_son;
            min_des[cnt]=cnt_min_des, min_des[son]=son_min_des;
        }
    }
}
int main() {
    int T; scanf("%d",&T);
    while(T--) {
        int n, m; scanf("%d%d",&n,&m);
        for(int i=0; i<n; ++i){
            G[i].clear(), Q[i].clear();
            vis[i]=false;
        }
        for(int i=1; i<n; ++i) {
            int a, b; scanf("%d%d",&a, &b);
            --a, --b;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        dfs(0);
        for(int i=0; i<m; ++i) {
            int x, y; scanf("%d%d",&x,&y);
            --x, --y;
            Q[x].push_back(make_pair(y, i));
        }
        memset(vis, false, sizeof(vis));
        dfs_ans(0);
        for(int i=0; i<m; ++i) {
            if(ans1[i]==maxn) puts("no answers!");
            else {
                printf("%d %d\n", ++ans1[i], ++ans2[i]);
            }
        }
        puts("");
    }
    return 0;
}


【树形DP】 HDU 4008 Parent and son

上一篇:获取每个月第一个星期日的日期


下一篇:slab 着色的理解