2020CCPC绵阳/gym102822 C. Code a Trie 贪心

2020CCPC绵阳/gym102822 C. Code a Trie

题意

随机生成一颗字典树,字典树上每个结点的权值都互不相同,给定\(n\)个询问串和返回值,问字典树中至少有多少个结点。

分析

  • 首先我们根据所有query建立字典树并记录\(sz[x]\)表示有多少个询问串经过点\(x\),那么对于同一个串,答案一定是同一个。

  • 我们对于每一个值

    • 计算对应串的LCA, 然后把LCA标记一下
    • 标记这些串在LCA下面的那个点为一定不存在
  • 每个点只能被一个值标记为LCA,根到LCA一定不能经过不存在的点

  • dfs贪心计算每个子树最少的节点

    • 如果这个点的\(sz[x]>=2\)

      • 这个点一定要选

      • 如果这个点是LCA,那么它的儿子结点都要选

      • 如果这个点不是LCA,它的儿子中\(sz[x]=1\)的结点至多有一个不选

    • 如果这个点的\(sz[x]=1\),它的儿子一定不选

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=5e5+10;
const int inf=1e9;
int T,n;
string s[N];
int a[N],b[N],cnt[N],vis[N],ans;
int tot,ch[N][30];
vector<string>g[N];
bool input(){
    cin>>n;
    int flag=1,m=0;
    rep(i,1,n){
        cin>>s[i]>>a[i];
        m+=sz(s[i]);
    }
    tot=0;
    rep(i,1,n) g[i].clear();
    rep(i,0,m+5) memset(ch[i],0,sizeof ch[i]);
    memset(cnt,0,sizeof(int)*(m+5));
    memset(vis,0,sizeof(int)*(m+5));
    return flag;
}
bool gao(vector<string> &v){
    //寻找LCA
    sort(v.begin(), v.end(),[](string x,string y){return sz(x)<sz(y);});
    int len=0;
    for(int i=0;i<sz(v[0]);i++){
        int flag=1;
        for(int j=0;j<sz(v)&&flag;j++){
            if(v[j][i]!=v[0][i]) flag=0;
        }
        if(!flag) break;
        else len=i+1;
    }
    //插入前缀
    int rt=0;
    for(int i=0;i<len;i++){
        cnt[rt]++;
        int c=v[0][i]-'a';
        if(ch[rt][c]==-1) return false;
        if(!ch[rt][c]) ch[rt][c]=++tot;
        rt=ch[rt][c];
    }
    //标记LCA
    if(vis[rt]) return false;
    vis[rt]=1;
    cnt[rt]++;
    //标记不存在结点
    for(int i=0;i<sz(v);i++) if(sz(v[i])>len){
        int c=v[i][len]-'a';
        if(ch[rt][c]>0) return false;
        ch[rt][c]=-1;
    }
    return true;
}
void dfs(int u){
    if(cnt[u]>1) ans++;
    int flag=vis[u]==0;
    for(int i=0;i<26;i++){
        int x=ch[u][i];
        if(x==0||x==-1) continue;
        if(cnt[x]==1){
            if(!flag) ans++;
            else flag=0; 
        }else dfs(x);
    }
}
void solve(int cas){
    int m=0;
    rep(i,1,n){
        b[++m]=a[i];
    }
    sort(b+1,b+m+1);
    m=unique(b+1,b+m+1)-b-1;
    rep(i,1,n){
        a[i]=lower_bound(b+1,b+m+1,a[i])-b;
        g[a[i]].pb(s[i]);
    }
    for(int i=1;i<=m;i++) if(!gao(g[i])){
        printf("Case #%d: -1\n",cas);
        return;
    }
    ans=0;
    cnt[0]++;//根节点必须选
    dfs(0);
    printf("Case #%d: %d\n",cas,ans);
}
int main(){
    ios::sync_with_stdio(false);
    cin>>T;
    for(int cas=1;cas<=T;cas++){
        input();
        solve(cas);
    }
    return 0;
}
posted @ 2020-11-20 23:46  xyq0220  阅读(289)  评论(0编辑  收藏  举报