[JZOJ5363]生命之树

来源:互联网 发布:iptv管理系统php 编辑:程序博客网 时间:2024/05/19 06:47

题目大意

给定一棵n个节点的树,1号节点为根每个节点上面有一个由小写字母组成的字符串Si和一个权值vali,两个字符串Si,Sj组合起来的收益为LCP(Si,Sj)
定义decuu子树内所有的点,那么以u为根的子树的总收益为

ansu=idecujdecu,i<j(vali xor valj)×LCP(Si,Sj)

对每一节点输出其子树的总收益。

2n105,0vali105,1u,vn,|Si|5×105


题目分析

看到异或运算直接拆位。
考虑维护一个子树的Trie,统计答案的话可以每一个节点开一个logval的数组记录某一位是0/1的节点由多少个,然后枚举Trie上节点。
然后我们直接用线段树合并的方法合并Trie同时更新答案就好了。
时间复杂度O(|Si|lognlogval)


代码实现

#include <iostream>#include <cstring>#include <cstdio>#include <cctype>using namespace std;typedef long long LL;int read(){    int x=0,f=1;    char ch=getchar();    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();    return x*f;}int buf[30];void write(LL x){    if (x<0) putchar('-'),x=-x;    for (;x;x/=10) buf[++buf[0]]=x%10;    if (!buf[0]) buf[++buf[0]]=0;    for (;buf[0];putchar('0'+buf[buf[0]--]));}const int N=100005;const int E=N<<1;const int L=500015;const int LGN=17;const int S=L+N;const int C=26;int val[N],last[N];int tov[E],nxt_[E];char str[L];LL ans[N];int n,tot;int cnt[S][LGN][2];int nxt[S][C];int root[N];int tots;int newnode(int val){    ++tots;    for (int i=0;i<LGN;++i,val>>=1) ++cnt[tots][i][val&1];    return tots;}void ins(int id,int val){    int rt=root[id]=newnode(0),len=strlen(str);    for (int i=0;i<len;++i) nxt[rt][str[i]-'a']=newnode(val),rt=nxt[rt][str[i]-'a'];}int merge(int x,int y,LL &ret){    if (!x||!y) return x^y;    for (int i=0;i<LGN;++i)    {        ret+=(1ll*cnt[x][i][0]*cnt[y][i][1]+1ll*cnt[x][i][1]*cnt[y][i][0])*(1<<i);        cnt[x][i][0]+=cnt[y][i][0],cnt[x][i][1]+=cnt[y][i][1];    }    for (int c=0;c<C;++c) nxt[x][c]=merge(nxt[x][c],nxt[y][c],ret);    return x;}void insert(int x,int y){tov[++tot]=y,nxt_[tot]=last[x],last[x]=tot;}void dfs(int x,int fa=0){    ans[x]=0;    for (int i=last[x],y;i;i=nxt_[i])        if ((y=tov[i])!=fa) dfs(y,x),ans[x]+=ans[y],root[x]=merge(root[x],root[y],ans[x]);}int main(){    freopen("tree.in","r",stdin),freopen("tree.out","w",stdout);    n=read();    for (int i=1;i<=n;++i) val[i]=read();    for (int i=1;i<=n;++i) scanf("%s",str),ins(i,val[i]);    for (int i=1,x,y;i<n;++i) x=read(),y=read(),insert(x,y),insert(y,x);    dfs(1);    for (int i=1;i<=n;++i) write(ans[i]),putchar('\n');    fclose(stdin),fclose(stdout);    return 0;}
原创粉丝点击