URAL_1542 用来恢复状态的
题目大意是有很多字符串s[],每个字符串对应一个分值。然后由若干询问,每个询问会给出一个前缀,让你把满足前缀的字符串都找出来,按照分值从大到小顺序输出,如果有很多的话,输出前10个
10 是这题的关键,于是我们可以把字符串按字典顺序sort一下,搞一棵线段树,每条线段保存该段中从大到小的十个元素。然后就询问线段树该前缀对应的区间好了。
编程上利用下STL的两个函数 merge() 归并两个有序的数组,然后copy()把一个数组的一部分复制到另一个一个数组。写下来就会很容易
//URAL_1542_Autocompletion
//By xt3000 Used G++
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
struct WORD{
string s;
int v;
friend bool operator < (const WORD& l,const WORD& r){
return l.s<r.s;
};
};
WORD a[100010];
bool cmp(const int &l,const int &r){
if (a[l].v==a[r].v)
return l<r;
else
return a[l].v>a[r].v;
};
struct STree{
int v[10];
};
int n,m;
STree s[400001];
int as[400001][10],as1[400001][10];
int temp[20],temp1[20];
void build(int p,int l,int r){
if (r-l<=9) {
for (int i=0;i<=r-l;i++) s[p].v[i]=l+i;
sort(s[p].v,s[p].v+10,cmp);
}else{
int mid=(l+r)/2;
build(p*2,l,mid);build(p*2+1,mid+1,r);
merge(s[p*2].v,s[p*2].v+10,s[p*2+1].v,s[p*2+1].v+10,temp,cmp);
copy(temp,temp+10,s[p].v);
};
};
void ask(int p,int l,int r,int st,int en,int ans[]){
if (l==st && r==en) {
merge(ans,ans+10,s[p].v,s[p].v+10,temp,cmp);
copy(temp,temp+10,ans);
}else if (en-st<=9) {
for (int i=0;i<=en-st;i++) temp1[i]=st+i;
sort(temp1,temp1+en-st+1,cmp);
merge(ans,ans+10,temp1,temp1+en-st+1,temp,cmp);
copy(temp,temp+10,ans);
}else{
int mid=(l+r)/2;
if (en<=mid) ask(p*2,l,mid,st,en,ans);
else if (st>mid) ask(p*2+1,mid+1,r,st,en,ans);
else {
fill(as[p],as[p]+10,0);fill(as1[p],as1[p]+10,0);
ask(p*2,l,mid,st,mid,as[p]);
ask(p*2+1,mid+1,r,mid+1,en,as1[p]);
merge(as[p],as[p]+10,as1[p],as1[p]+10,temp1,cmp);
merge(temp1,temp1+10,ans,ans+10,temp,cmp);
copy(temp,temp+10,ans);
};
};
};
int main(){
int i,j,k;
int ans[10];
string s;
WORD w;
cin>>n;
for (i=1;i<=n;i++) {
cin>>a[i].s>>a[i].v;
};
sort(a+1,a+1+n);
build(1,1,n);
cin>>m;
for (i=1;i<=m;i++) {
if (i>1) cout<<endl;
cin>>s;w.s=s;
j=lower_bound(a+1,a+1+n,w)-a;
if (j>n || a[j].s.length()<s.length() || a[j].s.substr(0,s.length())!=s) continue;
w.s+=char(255);
k=lower_bound(a+1,a+1+n,w)-a;k–;
fill(ans,ans+10,0);
ask(1,1,n,j,k,ans);
j=0;
while (j<10 && ans[j]>0) {
cout<<a[ans[j]].s<<endl;
j++;
};
};
return 0;
};
