Codeforces Round#333 div.1 D Acyclic Organic Compounds
2016-05-26 22:04
351 查看
题目大意是给你一棵还没有合并的trie树,要你合并它,然后统计一些傻逼信息。
本题需要一种线性时间复杂度的合并算法,这里直接给代码片了。
为什么这样是线性的呢?
假设有一个trie树的集合,按照这个算法,每次合并,merge会调用O(min(size[a],size[b]))次,所以调用是所有集合的点数和次,是线性的。
为什么我没有想出来,可能是因为我没怎么写过树的递归合并的题目,也就是代码能力差,结果就算想了也不敢写,甚至因为代码能力的限制而导致思维能力的局限。代码能力像是交通工具,越强就可以把思维承载得越远。我以前一直没有想过代码能力与思维能力之间的联系,总是孤立地看待,这样是有违辩证唯物主义的观点与方法的。今天总算是意识到了,继续加油喽。
本题需要一种线性时间复杂度的合并算法,这里直接给代码片了。
#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]))次,所以调用是所有集合的点数和次,是线性的。
为什么我没有想出来,可能是因为我没怎么写过树的递归合并的题目,也就是代码能力差,结果就算想了也不敢写,甚至因为代码能力的限制而导致思维能力的局限。代码能力像是交通工具,越强就可以把思维承载得越远。我以前一直没有想过代码能力与思维能力之间的联系,总是孤立地看待,这样是有违辩证唯物主义的观点与方法的。今天总算是意识到了,继续加油喽。
相关文章推荐
- 网页定位导航
- bzoj2638 黑白染色
- codeforces 675C Money Transfers map
- C++快速入门-默认参数
- 使用KOG数据库进行注释
- Implement Stack using Queues
- BZOJ3879 SvT
- linux常用命令详解(持续更新)
- accesskey属性 显示“快捷键清单”
- onSaveInstanceStat和onRestoreInstanceState调用时机
- css 的@media print控制打印
- 原型模式及php实现
- Uva 105 The Skyline Problem
- 2016"百度之星" - 初赛(Astar Round2A)
- Java高级之内存模型分析
- PHP复用curl请求遇到的请求参数混乱的问题
- Java Web网站搭建SSL证书的问题与解决方案
- Java高级之内存模型分析
- unity3d中OnEnable和Awake的顺序问题
- 浅谈Java中的hashcode方法