【题目】D. Acyclic Organic Compounds

【题意】给定一棵带点权树,每个点有一个字符,定义一个结点的字符串数为往下延伸能得到的不重复字符串数,求min(点权+字符串数),n<=300000,time=3s。

【算法】trie合并||hash+线段树合并||dsu on tree

【题解】维护每个节点的Trie,那么每个节点的不重复字符串数是Trie的节点数。

每个节点Tire的根设为这个节点的字符(不是空字符)

这样Trie的合并就很方便了,merge(a,b)表示将b并入a下一层,假设b的根字符为c:

如果存在trans(a,c),那么累计重叠一个节点,继续合并。

否则加入trans(a,c)=b,退出。

这样能统计出总共重叠多少个节点,merge结束后在size(a)中减去。

合并的复杂度分析和线段树合并分析相同,复杂度为$O(26*n)$。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
int n,tot,ans=,ansnum=,num[maxn],first[maxn],ch[maxn][],sz[maxn];
char s[maxn];
struct edge{int v,from;}e[maxn*];
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
int merge(int a,int b){
int x=s[b]-'a',sum;
if(ch[a][x]){
sum=;
for(int i=;i<;i++)if(ch[b][i])sum+=merge(ch[a][x],ch[b][i]);
}
else{
sum=;
ch[a][x]=b;
}
return sum;
}
void dfs(int x,int fa){
sz[x]=;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
dfs(e[i].v,x);
sz[x]+=sz[e[i].v];
sz[x]-=merge(x,e[i].v);
}
if(ans<num[x]+sz[x]){
ans=num[x]+sz[x];
ansnum=;
}else if(ans==num[x]+sz[x])ansnum++;
}
int main(){
n=read();
for(int i=;i<=n;i++)num[i]=read();
scanf("%s",s+);
for(int i=;i<n;i++){
int u=read(),v=read();
insert(u,v);insert(v,u);
}
dfs(,);
printf("%d\n%d",ans,ansnum);
return ;
}

hash+线段树合并:主要问题在于每次都会增加一个字符,取模后就破坏了原有顺序。

解决方法是,每个点记录从根到它的字符串的哈希值,两个遇到一起会消去的字符串一定从根开始就相同。

然后将这些哈希值离散化后线段树合并即可,复杂度O(n log n)。

平衡树+启发式合并,复杂度O(n log2n)。

注意:CodeForces卡自然溢出,可以取模1e18+7效果就和自然溢出差不多了。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define ul unsigned long long
using namespace std;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=,base=;
int n,tot,cnt,first[maxn],root[maxn],num[maxn],ans=,ansnum=;
ul g[maxn],h[maxn],MOD=;
char s[maxn];
struct tree{int l,r,sum;}t[maxn*];
struct edge{int v,from;}e[maxn*];
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void dfs(int x,int fa,ul num){
g[x]=h[x]=(1ull*num*base+s[x]+)%MOD;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
dfs(e[i].v,x,h[x]);
}
}
void build(int l,int r,int &k,int x){
if(!k)k=++cnt;t[k].sum=;
if(l==r)return;
int mid=(l+r)>>;
if(x<=mid)build(l,mid,t[k].l,x);
else build(mid+,r,t[k].r,x);
}
int merge(int l,int r,int a,int b){
if(!a||!b)return a^b;
if(l==r){t[a].sum=;return a;}
int mid=(l+r)>>;
t[a].l=merge(l,mid,t[a].l,t[b].l);
t[a].r=merge(mid+,r,t[a].r,t[b].r);
t[a].sum=t[t[a].l].sum+t[t[a].r].sum;
return a;
}
void ask(int x,int fa){
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
ask(e[i].v,x);
root[x]=merge(,tot,root[x],root[e[i].v]);
}
if(num[x]+t[root[x]].sum>ans){
ans=num[x]+t[root[x]].sum;
ansnum=;
}
else if(num[x]+t[root[x]].sum==ans)ansnum++;
}
int main(){
n=read();
for(int i=;i<=n;i++)num[i]=read();
scanf("%s",s+);
for(int i=;i<n;i++){
int u=read(),v=read();
insert(u,v);insert(v,u);
}
dfs(,,);
sort(g+,g+n+);
tot=unique(g+,g+n+)-g-;
for(int i=;i<=n;i++)h[i]=lower_bound(g+,g+tot+,h[i])-g;
for(int i=;i<=n;i++)build(,tot,root[i],h[i]);
ask(,);
printf("%d\n%d",ans,ansnum);
return ;
}

dsu on tree:见官方题解。

【CodeForces】601 D. Acyclic Organic Compounds的更多相关文章

  1. Codeforces Round #333 (Div. 1) D. Acyclic Organic Compounds trie树合并

    D. Acyclic Organic Compounds   You are given a tree T with n vertices (numbered 1 through n) and a l ...

  2. 【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环

    [题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一 ...

  3. 【Codeforces】Round #491 (Div. 2) 总结

    [Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...

  4. 【Codeforces】Round #488 (Div. 2) 总结

    [Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...

  5. 【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)

    没有参加,但是之后几天打了哦,第三场AK的CF比赛. CF大扫荡计划正在稳步进行. [A]Olympiad 题意: 给\(n\)个人颁奖,要满足: 至少有一个人拿奖. 如果得分为\(x\)的有奖,那么 ...

  6. 【Codeforces】849D. Rooter's Song

    [算法]模拟 [题意]http://codeforces.com/contest/849/problem/D 给定n个点从x轴或y轴的位置p时间t出发,相遇后按对方路径走,问每个数字撞到墙的位置.(还 ...

  7. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...

  8. 【CodeForces】925 C.Big Secret 异或

    [题目]C.Big Secret [题意]给定数组b,求重排列b数组使其前缀异或和数组a单调递增.\(n \leq 10^5,1 \leq b_i \leq 2^{60}\). [算法]异或 为了拆位 ...

  9. 【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块

    [题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...

随机推荐

  1. iOS关于setContentOffset的一些细节问题

    在UIScrollView,setContentOffset方法的功能是跳转到你指定内容的坐标, setContentOffset有两种方法:setContentOffset:和setContentO ...

  2. Thinkphp5的ajax接口实现

    前一篇讲到thinkphp5从数据库获取数据之后赋给视图view,前一篇从数据渲染方式来说是服务端数据渲染,这一章则是浏览器端数据渲染.按照知识总结依据来划分,这是两种不同的技术场景. 下面介绍具体的 ...

  3. 用svmpredict输出的结果为空

    源程序:

  4. 修改MSSQL字段类型

    update Data_Project set SyncTime=NULL; alter table Data_Project alter column SyncTime datetime; upda ...

  5. Delphi实现在数据库中存取图像

    向窗体上添加一个TListBox组件.一个TImage组件和一个TTable组件,设计完成的主界面如图1所示. 图1 主界面 本系统中需要设计一个新的基于Paradox 7的数据库Image.db,图 ...

  6. 【bzoj3174】[Tjoi2013]拯救小矮人 贪心+dp

    题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人,我们知道他从脚 ...

  7. NAT穿透(UDP打洞)

    1.NAT(Network Address Translator)介绍 NAT有两大类,基本NAT和NAPT. 1.1.基本NAT 静态NAT:一个公网IP对应一个内部IP,一对一转换 动态NAT:N ...

  8. CentOS 压缩(打包)和解压

    1.tar命令 -c 创建压缩文件 -x 解开压缩文件 -t 查看压缩包内有哪些文件 -z 用 Gzip压缩或解压 -j 用 bzip2压缩或解压 -v 显示压缩或解压的过程 -f 目标文件名,在 f ...

  9. LOJ2350:[JOI2017/2018决赛]月票购买——题解

    https://loj.ac/problem/2350 比较简单的题,为什么我实现得这么sb? 第一个包其实已经给了提示(第一个包的解法就是在S->T所有最短路径上的所有点到V的最短路的最小值. ...

  10. Mac安装mysqldb

    一. 安装mysql (一)下载地址 https://pan.baidu.com/s/1slw50LZ 安装成功后,在系统偏好设置里有MySQL图标,可以启动或关闭MySQL 二. Mysql roo ...