zoukankan      html  css  js  c++  java
  • [题解] [JSOI2015] 送礼物

    题面

    题解

    经典套路, 用树上前缀和的方式建出可持久化 Trie 树

    询问就树上差分一下就行

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    const int N = 100005; 
    using namespace std;
    
    int n, m, head[N], cnt, cnte, rt[N]; 
    struct edge { int to, nxt, len; string s; } e[N << 1];
    struct node { int ch[26], val; } t[N * 32]; 
    
    template < typename T >
    inline  T read()
    {
        T x = 0, w = 1; char c = getchar();
        while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * w; 
    }
    
    inline void adde(int u, int v, string s) { e[++cnte] = (edge) { v, head[u], s.size(), s }, head[u] = cnte; }
    
    void insert(int &p, int o, int x, int len, string s)
    {
        t[p = ++cnt] = t[o], t[p].val++; 
        if(x < len) insert(t[p].ch[s[x] - 'a'], t[o].ch[s[x] - 'a'], x + 1, len, s); 
    }
    
    namespace Treepou
    {
        int sz[N], dep[N], fa[N], son[N], top[N]; 
        void dfs1(int u, int pa)
        {
    	sz[u] = 1, dep[u] = dep[pa] + 1, fa[u] = pa;
    	for(int v, i = head[u]; i; i = e[i].nxt)
    	{
    	    v = e[i].to; if(v == pa) continue; 
    	    insert(rt[v], rt[u], 0, e[i].len, e[i].s); 
    	    dfs1(v, u), sz[u] += sz[v]; 
    	    if(sz[v] > sz[son[u]]) son[u] = v; 
    	} 
        }
        void dfs2(int x, int y)
        {
    	top[x] = y; if(!son[x]) return;
    	dfs2(son[x], y); 
    	for(int i = head[x]; i; i = e[i].nxt)
    	    if(e[i].to != fa[x] && e[i].to != son[x]) dfs2(e[i].to, e[i].to); 
        }
        int LCA(int u, int v)
        {
    	while(top[u] ^ top[v]) dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
    	return dep[u] < dep[v] ? u : v; 
        }
    };
    using namespace :: Treepou;
    
    int query(int p, string s)
    {
        int len = s.size(); 
        for(int i = 0; i < len; i++)
    	p = t[p].ch[s[i] - 'a']; 
        return t[p].val; 
    }
    
    int main()
    {
        n = read <int> (); 
        string s; rt[1] = ++cnt; 
        for(int u, v, i = 1; i < n; i++)
        {
    	u = read <int> (), v = read <int> (), cin>>s; 
    	adde(u, v, s), adde(v, u, s); 
        }
        dfs1(1, 0), dfs2(1, 1); 
        m = read <int> (); 
        for(int u, v, i = 1; i <= m; i++)
        {
    	u = read <int> (), v = read <int> (), cin>>s; 
    	printf("%d
    ", query(rt[u], s) + query(rt[v], s) - 2 * query(rt[LCA(u, v)], s)); 
        }
        return 0; 
    }
    
  • 相关阅读:
    最全的.NET Core跨平台微服务学习资源没有之一
    MySQL添加列、删除列,创建主键等常用操作总结
    SQL Server函数之空值处理
    SqlServer中循环和条件语句
    【转载】ASP.NET Core Web 支付功能接入 微信-扫码支付篇
    【转载】ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇
    Core知识整理
    C#对接----韵达开发平台--取电子面单
    Cookie 用法
    微信支付V3版本的那些事
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12358622.html
Copyright © 2011-2022 走看看