Luogu P3294 【[SCOI2016]背單詞】

閱讀理解題ios

。。。。。。spa

 



$Trie$

後綴問題很差處理,咱們把它轉化爲前綴問題,用字典樹解決問題

貪心

容易想到,一個串的後綴要先於它插入

對於一個串和其若干後綴串,容易想到,咱們要先插入後綴串

而後遞歸進入$size$最小的子串

指針

bool cmp(const int &x,const int &y)
{
    return size[x]<size[y];
}
void makes(int x)
{
    size[x]=1;
    for(int i=0;i<t[x].size();i++)
    {
        makes(t[x][i]);
        size[x]+=size[t[x][i]];
    }
    sort(t[x].begin(),t[x].end(),cmp);
}
void dfs(int x)
{
    id[x]=tot++;
    for(int i=0;i<t[x].size();i++)
    {
        ans+=tot-id[x];
        dfs(t[x][i]);
    }
}



注意

求$size$要重構樹,只保留關鍵點

由於我太蒻了,並不會指針,因此提供一個並查集重構樹的方法

在建$Trie$時給全部串的結尾和$Trie$樹的根節點標號,表示新樹中點的編號

code

void insert(const string &s,int id)
{
    int now=0,l=len[id];
    for(int i=0;i<l;i++)
    {
        int c=idx(s[i]);
        now=tr[now][c]?tr[now][c]:tr[now][c]=++cnt;
    }
    val[now]=id;
}



而後遍歷$Trie$樹,若是一個節點的子節點沒有被標號,就把它併入當前節點的集合;不然把這個子節點做爲當前節點所在集合的根的兒子(就是連一條邊)

blog

void make(int x)
{
    for(int v,i=0;i<26;i++)
        if(v=tr[x][i])
        {
            if(!val[v])
                f[v]=find(x);
            else
                t[val[find(x)]].push_back(val[v]);
            make(v);
        }
}



代碼:

遞歸

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
const int maxl=510010,maxn=1e5+10;
int n,tr[maxl][30],val[maxl],cnt,len[maxn],size[maxn],tot,f[maxl],id[maxn],ans;
vector<int>t[maxn];
string st[maxn];
inline int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
inline int idx(char c)
{
    return c-'a';
}
void insert(const string &s,int id)
{
    int now=0,l=len[id];
    for(int i=0;i<l;i++)
    {
        int c=idx(s[i]);
        now=tr[now][c]?tr[now][c]:tr[now][c]=++cnt;
    }
    val[now]=id;
}
void make(int x)
{
    for(int v,i=0;i<26;i++)
        if(v=tr[x][i])
        {
            if(!val[v])
                f[v]=find(x);
            else
                t[val[find(x)]].push_back(val[v]);
            make(v);
        }
}
bool cmp(const int &x,const int &y)
{
    return size[x]<size[y];
}
void makes(int x)
{
    size[x]=1;
    for(int i=0;i<t[x].size();i++)
    {
        makes(t[x][i]);
        size[x]+=size[t[x][i]];
    }
    sort(t[x].begin(),t[x].end(),cmp);
}
void dfs(int x)
{
    id[x]=tot++;
    for(int i=0;i<t[x].size();i++)
    {
        ans+=tot-id[x];
        dfs(t[x][i]);
    }
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        cin>>st[i];
        len[i]=st[i].length();
        for(int j=0;j<len[i]/2;j++)
            swap(st[i][j],st[i][len[i]-j-1]);
        insert(st[i],i);
    }
    for(int i=1;i<=cnt;i++)
        f[i]=i;
    make(0),makes(0),dfs(0);
    printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索