2018 计算之道初赛第二场 阿里巴巴的手机代理商(困难)(反向可持久化Trie)
阿里巴巴的手机代理商(困难)
阿里巴巴的手机代理商正在研究 infra 输入法的新功能。他们需要分析单词频率以改进用户输入法的体验。于是需要你在系统内核里面写一个 API。 API 有如下功能:
-
添加操作
添加操作格式为
insert barty 8
,意思为插入barty
这个单词,这个单词词频为 88 次。注意如果再次添加insert barty 8
操作时,就会将词频增加为 1616 次。(不会出现词频 \le 0≤0 的情况)。 -
删除操作
删除操作格式为
delete barty
,意思为删除所有barty
这个单词。如果当前没有删除的词汇,输出
Empty
并不计入版本号。 -
查询操作
查询操作格式为
query ty
,意思为查询当前版本以ty
结尾的单词词频总和。 -
修改操作
修改操作格式为
update ty tied
,意思为将所有结尾是ty
的单词更新为tied
结尾,比如barty
会变为bartied
。如果不存在以ty
结尾的单词,输出Empty
。如果已经存在以tied
结尾的单词,那么说明存在 conflict。不做合并,输出Conflict
并且不算做新版本。如果既不存在ty
结尾的单词,也已经存在以tied
结尾的单词,则输出Empty
。 -
旧版本查询操作
将操作 11,22,44 每次迭代更新都视为一个版本。版本间查询格式为
vquery ied 3
,意思为查询当前版本 -3−3的版本中,以ied
为结尾的单词的词频和。保证 当前版本 -− 退回版本 \ge 0≥0(00 号版本为空)。
输入格式
第一行读入一个整数 TT,代表数据组数。
每组数据的第一行读入一个整数 NN 代表操作数。
接下来 NN 行,每行形容一个操作。
保证数据满足 1 \le T \le 101≤T≤10,1 \le N \le 10^51≤N≤105,insert
和update
操作的字符串总长度之和 \le 10^6≤106,所有字符串长度 \le 10^6≤106,输入只有小写字母。
输出格式
输出题目中要求的结果。
样例说明
insert barty 8
之后生成版本 11。
update ty tied
之后生成版本 22。
insert party 9
之后生成版本 33。
delete barty
之后生成版本 44。
样例输入
1 10 insert barty 8 delete shawn update ty tied query tied insert party 9 update y ed query ty delete party vquery ied 2 vquery ed 1
样例输出
Empty 8 Conflict 9 8 8
题目来源
因为找结尾嘛,所以我们反向存string到Trie里,然后涉及多版本问题,怕空间不够用,写可持久化的时候加入了数组分配,拿个stack和set去动态分配。反正代码写完真长,debug一天2333。
被不成功不算更新版本坑了。。好气哦。。改一下就过了。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 7 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 #define mp make_pair 8 #define pb push_back 9 #define mp make_pair 10 #define fi first 11 #define se second 12 using namespace std; 13 const int N=1e6+10; 14 struct node 15 { 16 int next[26]; 17 LL num,ende; 18 }trie[3*N]; 19 stack<int> sta; 20 set<int> used; 21 int root[N],nowv,dt; 22 int makenode() 23 { 24 int tot=sta.top(); 25 sta.pop(); 26 used.insert(tot); 27 return tot; 28 } 29 int makenode(int i) 30 { 31 int tot=sta.top(); 32 sta.pop(); 33 used.insert(tot); 34 trie[tot]=trie[i]; 35 return tot; 36 } 37 void delnode(int i) 38 { 39 used.erase(i); 40 sta.push(i); 41 return ; 42 } 43 char s[N],s2[N]; 44 void add(char *s,LL d,int &root) 45 { 46 root=makenode(root); 47 int now=root,len=strlen(s),p; 48 for(int i=len-1;i>=0;i--) 49 { 50 p=s[i]-'a'; 51 if(!trie[now].next[p]) 52 trie[now].next[p]=makenode(); 53 else 54 trie[now].next[p]=makenode(trie[now].next[p]); 55 now=trie[now].next[p]; 56 trie[now].num+=d; 57 } 58 trie[now].ende+=d; 59 return ; 60 } 61 int pt[N]; 62 bool deleted(char *s,int &root) 63 { 64 root=makenode(root); 65 LL d; 66 int now=root,len=strlen(s),p; 67 for(int i=len-1;i>=0;i--) 68 { 69 p=s[i]-'a'; 70 if(!trie[now].next[p]) 71 return false; 72 now=trie[now].next[p]; 73 } 74 if(trie[now].ende==0) 75 return false; 76 d=trie[now].ende; 77 now=root; 78 for(int i=len-1;i>=0;i--) 79 { 80 p=s[i]-'a'; 81 trie[now].next[p]=makenode(trie[now].next[p]); 82 now=trie[now].next[p]; 83 trie[now].num-=d; 84 pt[i]=now; 85 } 86 trie[now].ende=0; 87 pt[len]=root; 88 for(int i=0;i<len;i++) 89 { 90 if(trie[pt[i]].num>0) 91 break; 92 trie[pt[i+1]].next[s[i]-'a']=0; 93 delnode(pt[i]); 94 } 95 return true; 96 } 97 LL query(char *s,int &root) 98 { 99 int now=root,len=strlen(s),p; 100 for(int i=len-1;i>=0;i--) 101 { 102 p=s[i]-'a'; 103 if(!trie[now].next[p]) 104 return 0; 105 now=trie[now].next[p]; 106 } 107 return trie[now].num; 108 } 109 int update(char *s1,char *s2,int &root) 110 { 111 root=makenode(root); 112 int now=root,len=strlen(s1),p; 113 for(int i=len-1;i>=0;i--) 114 { 115 p=s1[i]-'a'; 116 if(!trie[now].next[p]) 117 return 1; 118 now=trie[now].next[p]; 119 } 120 if(trie[now].num==0) 121 return 1; 122 LL d=trie[now].num; 123 now=root; 124 len=strlen(s2); 125 bool flag=0; 126 for(int i=len-1;i>=0;i--) 127 { 128 p=s2[i]-'a'; 129 if(!trie[now].next[p]) 130 { 131 flag=1; 132 break; 133 } 134 now=trie[now].next[p]; 135 } 136 if(flag==0) 137 return 2; 138 now=root; 139 len=strlen(s1); 140 for(int i=len-1;i>0;i--) 141 { 142 p=s1[i]-'a'; 143 trie[now].next[p]=makenode(trie[now].next[p]); 144 now=trie[now].next[p]; 145 trie[now].num-=d; 146 pt[i]=now; 147 } 148 int pt1=trie[now].next[s1[0]-'a']; 149 trie[now].next[s1[0]-'a']=0; 150 pt[len]=root; 151 for(int i=1;i<len;i++) 152 { 153 if(trie[pt[i]].num>0) 154 break; 155 trie[pt[i+1]].next[s[i]-'a']=0; 156 delnode(pt[i]); 157 } 158 now=root; 159 len=strlen(s2); 160 for(int i=len-1;i>0;i--) 161 { 162 p=s2[i]-'a'; 163 if(!trie[now].next[p]) 164 trie[now].next[p]=makenode(); 165 else 166 trie[now].next[p]=makenode(trie[now].next[p]); 167 now=trie[now].next[p]; 168 trie[now].num+=d; 169 } 170 int pt2=now; 171 trie[pt2].next[s2[0]-'a']=pt1; 172 return 0; 173 } 174 int T,n,m; 175 LL d; 176 int main() 177 { 178 scanf("%d",&T); 179 for(int i=1;i<=3000000;i++) 180 sta.push(i); 181 while(T--) 182 { 183 root[0]=0; 184 nowv=0; 185 memset(&trie[0],0,sizeof(trie[0])); 186 scanf("%d",&n); 187 for(int i=1;i<=n;i++) 188 { 189 scanf("%s",s); 190 if(strcmp(s,"insert")==0) 191 { 192 scanf("%s%lld",s,&d); 193 ++nowv; 194 add(s,d,root[nowv]=root[nowv-1]); 195 } 196 else if(strcmp(s,"delete")==0) 197 { 198 scanf("%s",s); 199 ++nowv; 200 if(!deleted(s,root[nowv]=root[nowv-1])) 201 { 202 printf("Empty\n"); 203 nowv--; 204 } 205 206 } 207 else if(strcmp(s,"query")==0) 208 { 209 scanf("%s",s); 210 printf("%lld\n",query(s,root[nowv])); 211 } 212 else if(strcmp(s,"update")==0) 213 { 214 scanf("%s%s",s,s2); 215 nowv++; 216 int k=update(s,s2,root[nowv]=root[nowv-1]); 217 if(k==1) 218 { 219 printf("Empty\n"); 220 nowv--; 221 } 222 if(k==2) 223 { 224 printf("Conflict\n"); 225 nowv--; 226 } 227 } 228 else if(strcmp(s,"vquery")==0) 229 { 230 scanf("%s%d",s,&dt); 231 printf("%lld\n",query(s,root[nowv-dt])); 232 } 233 } 234 for(auto p:used) 235 { 236 memset(&trie[p],0,sizeof(trie[p])); 237 sta.push(p); 238 } 239 used.clear(); 240 } 241 return 0; 242 }