小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\n",ans);
    return 0;
}

 

posted on 2020-08-08 22:12  mmn  阅读(156)  评论(0编辑  收藏  举报