zoukankan      html  css  js  c++  java
  • 小H和遗迹

    小H和遗迹

    dfs+trie+树状数组

    解:这个题满足一个结论,假设我们当前要比较字符串A和字符串B是不是满足的,假设l1为字符串开头位置到第一个‘#’的前缀,s1为字符串倒序中到最后一个'#‘的后缀。

    同理l2和s2.如果字符串A和字符串B是满足题目条件的,那么l1和l2中,肯定有一个是另外一个的前缀。s1和s2中,肯定有一个是另外一个的后缀.

    首先需要建立两颗trie树,正序一颗,后序一颗。对于每一个字符串,我们保存当前前缀中第一个'#'之前的前一个坐标x1和当前后缀中最后一个'#'后面的第一个点的坐标x2,然后建图保存x1->x2。

    当前这个人的贡献 就是 后序trie树上这个节点v的祖先节点中已经储存了多少人 + 这个节点所代表的子树中已经储存了多少人。正好对应了当前这个后缀是别人的后缀 以及 别人的后缀 是 当前这个后缀 的后缀 这两种情况。

    具体的代码实现:

    对后序字典序跑一个dfs序,因为需要用到区间的信息。每一次查询的时候,对于当前 后序trie树上这个节点v的祖先节点中已经储存了多少人 的相对应的信息,

    可以开一个树状数组维护这个节点到根节点的人的个数。对于 这个节点所代表的子树中已经储存了多少人 这个信息,我们需要另外再开一个树状数组维护这个区间的信息(如果用一个的话会算重),这个区间对答案的贡献就是以当前节点所代表的的子树中有多少人... trie不是很熟悉...题解参考这个人...

     

    代码:

    #include <bits/stdc++.h>
     
    using namespace std;
    typedef long long ll;
     
    const int maxn = 1e6+9;
     
    char s[maxn];
     
    int id(char s){
        return s-'a';
    }
     
    struct tire{
        int cnt;
        int _next[maxn][26];
        int insert(char s[]){
            int p=0;
            for(int i=0;s[i];i++){
                if(s[i]=='#')break;
                if(!_next[p][id(s[i])]){
                    _next[p][id(s[i])]=++cnt;
                }
                p=_next[p][id(s[i])];
            }
            return p;
        }
    }T1,T2;
     
    struct BIT{
        int bit[maxn];
        int n=1e6;
        void add(int x,int y){
            while(x<=n){
                bit[x]+=y;
                x+=(x&-x);
            }
        }
        ll query(int x){
            ll ans=0;
            while(x){
                ans+=bit[x];
                x-=(x&-x);
            }
            return ans;
        }
    }T3,T4;
     
    vector<int>G[maxn];
     
    int dfn;
    int be[maxn],en[maxn];
     
    void dfs1(int u){
        be[u]=++dfn;
        for(int i=0;i<26;i++){
            if(T1._next[u][i]){
                dfs1(T1._next[u][i]);
            }
        }
        en[u]=dfn;
    }
     
    ll ans=0;
     
    void dfs2(int u){
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            ans+=T3.query(be[v]);
            T3.add(be[v],1);
            T3.add(en[v]+1,-1);
            ans+=T4.query(en[v])-T4.query(be[v]);
            T4.add(be[v],1);
        }
        for(int i=0;i<26;i++){
            if(T2._next[u][i]){
                dfs2(T2._next[u][i]);
            }
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            T3.add(be[v],-1);
            T3.add(en[v]+1,1);
            T4.add(be[v],-1);
        }
     
    }
     
    int main(){
        int n;scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int len=strlen(s);
            int x=T1.insert(s);
            reverse(s,s+len);
            int y=T2.insert(s);
            G[y].push_back(x);
        }
        dfs1(0);
        dfs2(0);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    redis持久化RDB和AOF
    线程同步的几种方法
    JRE和JDK的区别
    Spring-两种配置容器
    为什么String类是不可变的?
    Oracle 每五千条执行一次的sql语句
    Executor , ExecutorService 和 Executors
    常见框架单例、多例与线程安全性总结
    mysql 的S 锁和X锁的区别
    linux下使用shell脚本自动化部署项目
  • 原文地址:https://www.cnblogs.com/sweetlittlebaby/p/13460647.html
Copyright © 2011-2022 走看看