题意:每次询问:输出当前自库中以之为前缀的字符串频率最大的(相等时字典序最小)的字符串。 此题开始就跪,字典树不是问题,关键是解决每次输出就是把这个串在字典树跑了一遍之后(停在某 节点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 ",ss); insert(s); } return 0; }