题意:每次询问:输出当前自库中以之为前缀的字符串频率最大的(相等时字典序最小)的字符串。
此题开始就跪,字典树不是问题,关键是解决每次输出就是把这个串在字典树跑了一遍之后(停在某
节点node),输出以node为根节点的子树中的权值最大的“终止节点”,这个问题,开始走w[u]最大的,
发现不行啊(反例很多),后来发现,给每个结点加一个状态,记录以它为根的子树中,权最大的串,
(当然还有权值),,每插入一个串后,w[u]更新(u为终止结点),跟新每个结点的属性即可。
#include<iostream>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int tree[310000][27]; //字典树
struct node //结点属性
{
int maxchild;
string cs;
};node nodes[310000];
int w[310100];
int numv=0; //点数
int n;
void insert(string s) //插入s
{
queue<int>q; //再走一遍更新之用。
int u=0;
int len=s.size();
for(int i=0;i<len;i++)
{
q.push(u);
if(tree[u][s[i]-'a']==0)
{
tree[u][s[i]-'a']=++numv;
}
u=tree[u][s[i]-'a'];
}
q.push(u);
w[u]++;
while(!q.empty())
{
int cur=q.front();
q.pop();
if(nodes[cur].maxchild<w[u]) //更新
{
nodes[cur].maxchild=w[u];
nodes[cur].cs=s;
}
else
if(nodes[cur].maxchild==w[u])
{
if(nodes[cur].cs>s)
nodes[cur].cs=s;
}
}
}
string find(string s) //查找
{
int u=0;
int len=s.size();
for(int i=0;i<len;i++)
{
if(tree[u][s[i]-'a']==0)
return s;
u=tree[u][s[i]-'a'];
}
return nodes[u].cs;
}
int main()
{
char ss[15];
scanf("%d",&n);
string s;
for(int i=0;i<n;i++)
{
scanf("%s",ss);
s=ss;
string ts=find(s);
strcpy(ss,ts.c_str());
printf("%s\n",ss);
insert(s);
}
return 0;
}
转载于:https://www.cnblogs.com/yezekun/p/3925735.html