zoukankan      html  css  js  c++  java
  • Codeforces965E Short Code 【启发式合并】【堆】

    题目大意:

      给出总长度不超过1E+5的不重复字符串集,给每个字符串选一个前缀使得可以区分它。

    题目分析:

      KAN出的DIV2难度一般不高,想升Ranting的可以试试。

      简单的树上启发式合并,建出Trie树,一开始每个字符串用自己表示,每次向上合并的时候选出堆中最大元素变成当前位置,特判一下有end的地方即可。

      证明也很简单,我们考虑一个根没被选的子树,若我们要使得这个子树的代价最小,那么我们一定要选择一个位置放到根上来,不难发现选择深度最大的点是会最小的。由于树的子结构的关系,这样向上归纳也是正确的。

    代码:

      

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int sigma = 26;
     5 
     6 int n,num,len,root;
     7 char str[105000];
     8 struct trie{
     9     int end,sz,nxt[30];
    10 }T[105000];
    11 
    12 int Num(char ch){return ch-'a';}
    13 
    14 void insert(int now,int pla){
    15     if(pla == len) {T[now].sz++;T[now].end=1;return;}
    16     int um = Num(str[pla]);
    17     if(T[now].nxt[um]){
    18     insert(T[now].nxt[um],pla+1);
    19     }else{
    20     num++; T[now].nxt[um] = num;
    21     insert(T[now].nxt[um],pla+1);
    22     }
    23 }
    24 
    25 void dfs(int now){
    26     for(int i=0;i<sigma;i++)
    27     if(T[now].nxt[i]) dfs(T[now].nxt[i]),T[now].sz+=T[T[now].nxt[i]].sz;
    28 }
    29 
    30 void read(){
    31     scanf("%d",&n);
    32     for(int i=1;i<=n;i++){
    33     scanf("%s",str);
    34     len = strlen(str);
    35     insert(root,0);
    36     }
    37     dfs(root);
    38 }
    39 
    40 int ans = 0;
    41 int bel[102000];
    42 priority_queue<int,vector<int>,less<int> > q[102000];
    43 
    44 int merge(int a,int b){
    45     if(q[a].size()<q[b].size()){
    46     while(!q[a].empty()){
    47         int k = q[a].top();q[a].pop();
    48         q[b].push(k);
    49     }
    50     return b;
    51     }else{
    52     while(!q[b].empty()){
    53         int k = q[b].top();q[b].pop();
    54         q[a].push(k);
    55     }
    56     return a;
    57     }
    58 }
    59 
    60 void dfs2(int now,int val){
    61     int flag = false;
    62     for(int i=0;i<sigma;i++){
    63     if(T[now].nxt[i]) flag=true,dfs2(T[now].nxt[i],val+1);
    64     }
    65     if(!flag){bel[now]=++num;q[num].push(val);return;}
    66     for(int i=0;i<sigma;i++){
    67     if(T[now].nxt[i]){
    68         if(bel[now]){bel[now]=merge(bel[now],bel[T[now].nxt[i]]);}
    69         else bel[now] = bel[T[now].nxt[i]];
    70     }
    71     }
    72     if(T[now].end){
    73     q[bel[now]].push(val);
    74     }else{
    75     q[bel[now]].pop();
    76     q[bel[now]].push(val);
    77     }
    78 }
    79 
    80 void work(){
    81     num = 0;
    82     for(int i=0;i<sigma;i++){
    83     if(!T[root].nxt[i]) continue;
    84     dfs2(T[root].nxt[i],1);
    85     int hh = bel[T[root].nxt[i]];
    86     while(!q[hh].empty()){
    87         ans += q[hh].top();q[hh].pop();
    88     }
    89     }
    90     printf("%d",ans);
    91 }
    92 
    93 int main(){
    94     read();
    95     work();
    96     return 0;
    97 }
  • 相关阅读:
    ATmega328P定时器详解
    成员指针与mem_fn
    引用传参与reference_wrapper
    定位new表达式与显式调用析构函数
    模板参数的“右值引用”是转发引用
    C++生成随机数
    测量C++程序运行时间
    Snmp扫描-snmpwalk、snmpcheck
    操作系统识别-python、nmap
    服务扫描-dmitry、nmap、amap和服务识别
  • 原文地址:https://www.cnblogs.com/Menhera/p/8961932.html
Copyright © 2011-2022 走看看