【CodeForces】601 D. Acyclic Organic Compounds
【题目】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的更多相关文章
- 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 ...
- 【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环
[题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一 ...
- 【Codeforces】Round #491 (Div. 2) 总结
[Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...
- 【Codeforces】Round #488 (Div. 2) 总结
[Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...
- 【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)
没有参加,但是之后几天打了哦,第三场AK的CF比赛. CF大扫荡计划正在稳步进行. [A]Olympiad 题意: 给\(n\)个人颁奖,要满足: 至少有一个人拿奖. 如果得分为\(x\)的有奖,那么 ...
- 【Codeforces】849D. Rooter's Song
[算法]模拟 [题意]http://codeforces.com/contest/849/problem/D 给定n个点从x轴或y轴的位置p时间t出发,相遇后按对方路径走,问每个数字撞到墙的位置.(还 ...
- 【CodeForces】983 E. NN country 树上倍增+二维数点
[题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...
- 【CodeForces】925 C.Big Secret 异或
[题目]C.Big Secret [题意]给定数组b,求重排列b数组使其前缀异或和数组a单调递增.\(n \leq 10^5,1 \leq b_i \leq 2^{60}\). [算法]异或 为了拆位 ...
- 【CodeForces】700 D. Huffman Coding on Segment 哈夫曼树+莫队+分块
[题目]D. Huffman Coding on Segment [题意]给定n个数字,m次询问区间[l,r]的数字的哈夫曼编码总长.1<=n,m,ai<=10^5. [算法]哈夫曼树+莫 ...
随机推荐
- jspSmartUpload上传下载使用例子
--------------------------------------------------------------------- ServletUpload.java 上传 package ...
- ACM 第十九天
积性函数 积性函数线性筛,筛素数,u(n),欧拉函数: vis[]=vis[]=,mu[]=,phi[]=; ;i<=N;++i){ ,phi[i]=i-,prime[++cnt]=i; ,k= ...
- parse_str — 将字符串解析成多个变量
$arr2="first=value1&second=value2&third[]=value3&third[]=value4"; parse_str($a ...
- ResultSet 可滚动性和可更新性
JDBC 2.0 API 为结果集增加了两个新的基本能力:可滚动性和可更新性,我想肯定满足了你的要求.在滚动结果集中可用的方法有: rs.previous();//向前滚动 rs.next();//向 ...
- MYsql 数据库密码忘记(Window)-2(mysql 5.7)
很久没用Mysql了,再次打开,发现用不了了,密码忘了,服务也无法打开,在cmd中输入mysql之后,显示不是内部指令. 看来问题是mysql服务打不开了 (1)在cmd中 输入net start m ...
- WPF DataGrid的使用
构造数据: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sy ...
- VBA 练习-从两个库中调用数据到活动表中
练习VBA Sub 填报入库单() Dim basedb As String, cpdb As String, wb As Workbook, ws As Worksheet, curWs As Wo ...
- Qt安装与入门
一.Qt SDK1.2安装 准备QtSdk-offline-win-x86-v1_2_1.exe离线安装包. 安装QtSDK时注意不要有中文路径,空格以及特殊字符.可以自定义选择组件安装,也可以默认安 ...
- Wannafly 挑战赛16 A 取石子
题目描述 给出四堆石子,石子数分别为a,b,c,d.规定每次只能从堆顶取走石子,问取走所有石子的方案数. 输入描述: 在一行内读入四个由空格分隔的整数a,b,c,d, 输入均为不超过500的正整数 输 ...
- BZOJ3040:最短路——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3040 题意rt,使用pb_ds的堆解决本问题. 所以其实就是mark一下的. 不过有人确认过官方不 ...