【题目】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. JavaScript初探系列之String的基本操作

    1.字符串转换 字符串转换是最基础的要求和工作,你可以将任何类型的数据都转换为字符串,你可以用下面三种方法的任何一种: var myStr = num.toString(); // "19& ...

  2. dataTables工作总结

    近期在工作中用到了dataTables,现在总结一下在工作中遇到的问题以及解决方法,如有不妥之处希望多多指教,定会改进. 首先这里用的是coloradmin框架,在vs环境下开发. 这里写一个容器用于 ...

  3. js移动端滑块验证解锁组件

    本文修改自PC端的js滑块验证组件,PC端使用的是onmousedown,onmouseup,nomousemove.原文找不到了,也是博客园文章,在此感谢广大网友的生产力吧. 说下对插件和组件的理解 ...

  4. ES6之 =>箭头函数

    原文,请点此链接http://www.cnblogs.com/allenxieyusheng/p/5784728.html 1. 第一个函数 ()=>1 解析:其实这是一个匿名函数直接执行 (f ...

  5. 查看OpenWrt的RAM和FLASH

    加入了博客园,这是第一篇博文,不多写了,从以前博客搬东西过来吧. 买来一个OpenWrt的路由器,今天刚到的货,赶快拆开看看是不是替我换了RAM和FLASH的.那么怎么查看它是不是真的有那么大呢? 在 ...

  6. python2 对URL编码进行编译

    在请求页面时有时会返回类似: %E8%AF%A5985%E5%A4%A7%E5%AD%A6%E5%B8%B8%E5%B9%B4%E4%BD%8D%E5%B1%85%E5%9B%BD%E5%86%85% ...

  7. C#下载网页

    System.Net.WebClient wc = new System.Net.WebClient(); Byte[] pageData = wc.DownloadData("网页地址&q ...

  8. ASP.NET MVC4中使用bootstrip模态框时弹不出的问题

    最近发现使用在MVC中使用bootstrip的模态框时弹不出来,但单独建立一HTML文件时可以弹出,说明代码没有问题,经过多次测试发现,在MVC的cshtml文件中添加上以下语句就能正常 @{ Lay ...

  9. java计算某日期之后的日期

    public static void main(String[] args) { // 时间表示格式可以改变,yyyyMMdd需要写例如20160523这种形式的时间 SimpleDateFormat ...

  10. RT-thread内核之系统时钟

    一.系统时钟 rt-thread的系统时钟模块采用全局变量rt_tick作为系统时钟节拍,该变量在系统时钟中断函数中不断加1.而系统时钟中断源和中断间隔一般由MCU硬件定时器(如stm32的嘀嗒定时器 ...