题目链接:点击查看
题目分析:初始时给出一棵以点 0 0 0 为根节点的字典树,设 a r r i arr_i arri 为从根节点出发到达点 i i i 的字符串,需要回答对于每个 i ∈ [ 1 , n ] i\in[1,n] i∈[1,n] 时的 ∑ k = 1 n f ( a r r i , a r r k ) \sum_{k=1}^{n}f(arr_i,arr_k) ∑k=1nf(arri,arrk),其中 f ( s , t ) f(s,t) f(s,t) 代表的是字符串 s s s 在字符串 t t t 中出现的次数
需要注意的一个小坑点就是,因为字典树上的字符串总长最大可能是 O ( n 2 ) O(n^2) O(n2) 级别的,所以答案可能会爆 i n t int int,记得开 l o n g l o n g long\ long long long
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
代码:
// Problem: Elo mountains
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/17148/G
// Memory Limit: 1048576 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){
if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){
x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e5+100;
const int M=1e5;
vector<pair<int,int>>edge[N];//原树
vector<int>node[N];//fail树
unordered_map<int,int>trans[N];//原树的字典树
struct Node {
int l,r,val;
}tree[N*20];//可持久化数组
int trie[N],fail[N],tot;
LL dp[N],sz[N];
int newnode() {
tot++;
tree[tot].l=tree[tot].r=tree[tot].val=0;
return tot;
}
void add(int &k,int pos,int val,int l,int r) {
int nk=newnode();
tree[nk]=tree[k];
k=nk;
if(l==r) {
tree[k].val+=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) {
add(tree[k].l,pos,val,l,mid);
} else {
add(tree[k].r,pos,val,mid+1,r);
}
}
int ask(int k,int pos,int l,int r) {
if(l==r) {
return tree[k].val;
}
int mid=(l+r)>>1;
if(pos<=mid) {
return ask(tree[k].l,pos,l,mid);
} else {
return ask(tree[k].r,pos,mid+1,r);
}
}
void getfail() {
queue<int>q;
for(auto it:trans[0]) {
int u=0,v=it.second,to=it.first;
add(trie[u],to,v,1,M);
fail[v]=u;
q.push(v);
}
while(q.size()) {
int u=q.front();
q.pop();
trie[u]=trie[fail[u]];
for(auto it:trans[u]) {
int v=it.second,to=it.first;
int delta=v-ask(trie[u],to,1,M);
add(trie[u],to,delta,1,M);
fail[v]=ask(trie[fail[u]],to,1,M);
q.push(v);
}
}
}
void buildfail(int n) {
for(int i=1;i<=n;i++) {
dp[fail[i]]+=sz[i];
node[fail[i]].push_back(i);
}
}
void dfs1(int u,int fa) {
sz[u]=1;
for(auto it:edge[u]) {
int v=it.first,to=it.second;
if(v==fa) {
continue;
}
trans[u][to]=v;
dfs1(v,u);
sz[u]+=sz[v];
}
}
void dfs2(int u) {
for(auto v:node[u]) {
dfs2(v);
dp[u]+=dp[v];
}
}
void init() {
tot=-1;
newnode();
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
init();
int n;
read(n);
for(int i=1;i<=n;i++) {
int u,v,w;
read(u),read(v),read(w);
edge[u].push_back({
v,w});
edge[v].push_back({
u,w});
}
dfs1(0,-1);//建字典树
getfail();//得到fail边
buildfail(n);//建fail树
dfs2(0);//fail树上dp
for(int i=1;i<=n;i++) {
printf("%lld\n",dp[i]+sz[i]);
}
return 0;
}