Codeforces Round#333 div.1 D Acyclic Organic Compounds

题目大意是给你一棵还没有合并的trie树,要你合并它,然后统计一些傻逼信息。
本题需要一种线性时间复杂度的合并算法,这里直接给代码片了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cassert>
#include<map>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<climits>
#define X first
#define INF 0x3f3f3f3f
#define Y second
#define LL long long
#define DB double
#define pii pair<int,int>
#define MP make_pair
#define pb push_back
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<class T>void Read(T& x)
{
    x=0;int flag=0,sgn=1;char c;
    while(c=getchar())
    {
        if(c=='-')sgn=-1;
        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
        else if(flag)break;
    }
    x*=sgn;
}
const int MAXN=601000,MAXM=2*MAXN;
int ans1=0, ans2=0;
int n,c[MAXN],ch[MAXN][26],size[MAXN],sz=n;
char s[MAXN];
vector<int> G[MAXN];
void add(int a,int b)
{
    G[a].pb(b),G[b].pb(a);
}
bool cmp(int a,int b)
{
    return s[a]<s[b];
}
int merge(int u, int v)
{
    if(!u||!v)
        return u|v;
    //fprintf(stderr,"%d\n",sz);
    int o=++sz;
    assert(o!=1);
//  assert(
    size[o]=1;
    for(int i=0;i<26;i++)
    {
        ch[o][i]=merge(ch[u][i],ch[v][i]);
        //assert(ch[o][i]!=1);
        size[o]+=size[ch[o][i]];
    }
    return o;
}
void dfs(int u,int f)
{
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==f)
            continue;
        dfs(v,u);
    }
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==f)
            continue;
        ch[u][s[v]-'a']=merge(ch[u][s[v]-'a'],v);
    }
    for(int i=0;i<26;i++)
        size[u]+=size[ch[u][i]];
    size[u]++;
    if(size[u]+c[u]>ans1)
        ans1=size[u]+c[u],ans2=1;
    else
        ans2+=(size[u]+c[u]==ans1);
}
int main()
{
    //freopen("4.in","r",stdin);
    //freopen("4.out","w",stdout);
    Read(n);
    sz=n;
    for(int i=1;i<=n;i++)
        Read(c[i]);
    scanf("%s",s+1);
    for(int i=1;i<n;i++)
    {
        int a,b;
        Read(a),Read(b);
        add(a,b);
    }
    dfs(1,0);
    printf("%d\n%d\n",ans1,ans2);
}

为什么这样是线性的呢?
假设有一个trie树的集合,按照这个算法,每次合并,merge会调用O(min(size[a],size[b]))次,所以调用是所有集合的点数和次,是线性的。
为什么我没有想出来,可能是因为我没怎么写过树的递归合并的题目,也就是代码能力差,结果就算想了也不敢写,甚至因为代码能力的限制而导致思维能力的局限。代码能力像是交通工具,越强就可以把思维承载得越远。我以前一直没有想过代码能力与思维能力之间的联系,总是孤立地看待,这样是有违辩证唯物主义的观点与方法的。今天总算是意识到了,继续加油喽。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值