codeforces 778C. Peterson Polyglot(trie启发式合并,dfs,好题)

题目链接

题意:给出一棵 \(n\) 个结点 \(m\) 条边的 \(trie\) 树,树的深度从 \(0\) 开始,现要求删掉一层结点(删掉该层结点后下面的结点可能可以合并)使得剩下的点最少,输出最少的结点树并输出删除哪一层。

题解:这一题直接暴力枚举删除 \(i+1\) 层,然后把 \(i+2\) 层的子树进行\(trie\)启发式合并,算合并后结点数即可。

详见代码!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=3e5+100;
int head[maxn];
struct edge
{
    int to,next,w;
}e[maxn*2];   //
int tol=0;
void add(int u,int v,int w)
{
    e[++tol].to=v,e[tol].w=w,e[tol].next=head[u],head[u]=tol;
}
int ans[maxn];  //ans[i]表示删去deep[i]+1层减少的结点数目
int sz[maxn*2],deep[maxn],c[maxn*2][27];
int cnt;
int n;

int merge(int a,int b)
{
    if(!a||!b) return a|b;  //当a或b为空结点时返回非空结点,全为空时返回0
    int rt=++cnt;
    sz[rt]=1;
    for(int i=0;i<26;i++)
    {
        c[rt][i]=merge(c[a][i],c[b][i]); //递归,这里要记录c[rt][i]结点值因为是多棵树两两合并
        sz[rt]+=sz[c[rt][i]];
    }
    return rt;
}

void dfs(int u,int f)
{
    sz[u]=1;
    bool f1=false;  //判断结点u是否为叶子结点
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f) continue;
        f1=true;
        deep[v]=deep[u]+1;
        c[u][e[i].w]=v;
        dfs(v,u);
        sz[u]+=sz[v];
    }
    ans[deep[u]]+=sz[u];
    cnt=n;
    int p=0;
    for(int i=0;i<26;i++) p=merge(p,c[u][i]);
    if(f1)
    ans[deep[u]]-=sz[p]; //当不是叶子结点时可以删去下一层
    else ans[deep[u]]-=1;  //当是叶子结点时不能删去下一层,此时对该层贡献的答案应该为0.
}

int main()
{
    scanf("%d",&n);
    rep(i,1,n)
    {
        int u,v;
        char s[10];
        scanf("%d%d%s",&u,&v,s);
        add(u,v,s[0]-'a');
        add(v,u,s[0]-'a');
    }
    dfs(1,0);
    int p=0;
    rep(i,1,n) if(ans[i]>ans[p]) p=i;
    printf("%d\n%d\n",n-ans[p],p+1);
    return 0;
}
posted @ 2017-09-08 17:19  tarjan's  阅读(219)  评论(1编辑  收藏  举报