码迷,mamicode.com
首页 > 其他好文 > 详细

【FZU2280】Magic

时间:2018-04-27 02:32:19      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:长度   print   fzu   lap   个数   操作   img   splay   后缀数组   

题意

  给出n个字符串,每个字符串有一个权值wi 有q个操作,操作有两种 1 x y 将字符串x的权值变为y 2 x 查询操作,输出以字符串x为后缀,且权值小于等于wx的字符串个数。其中n<=1000 每个字符串长度<=1000 询问q<=80000。

分析

  n并不大,但是q太大了。如果暴力的话,每次查询都是o(n*len)的,肯定不行。

  等等,谁说不行?我试试 emmm。。。爆过去了????下面是瞎几把爆的代码:

技术分享图片
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=1000+10;
 8 int len[maxn],w[maxn];
 9 char s[maxn][maxn];
10 int T,n,q;
11 
12 int main(){
13     scanf("%d",&T);
14     for(int t=1;t<=T;t++){
15         scanf("%d",&n);
16         for(int i=1;i<=n;i++){
17             scanf("%s",s[i]);
18             scanf("%d",&w[i]);
19             len[i]=strlen(s[i]);
20         }
21         scanf("%d",&q);
22         int opt;
23         for(int i=1;i<=q;i++){
24             scanf("%d",&opt);
25             if(opt==1){
26                 int x,y;
27                 scanf("%d%d",&x,&y);
28                 w[x]=y;
29             }else if(opt==2){
30                 int x;
31                 scanf("%d",&x);
32                 int ans=0;
33                 for(int j=1;j<=n;j++){
34                     if(w[j]>w[x])continue;
35                     if(len[j]<len[x])continue;
36                     bool ok=1;
37                     for(int k=len[j]-1,l=len[x]-1;l>=0;k--,l--){
38                         if(s[x][l]!=s[j][k]){
39                             ok=0;
40                             break;
41                         }
42                     }
43                     if(ok){
44                         ans++;
45                        // cout<<j<<endl;
46                     }
47                 }
48                 printf("%d\n",ans);
49             }
50         }
51     }
52 return 0;
53 }
View Code

好吧好吧,上面那个不算,我们重新来想···

 后缀嘛,后缀数组?咳,我就知道名字而已不会。。想点会的。。

  字典树行不行?我们只要把字符串倒着插进去就可以用统计前缀的方法来统计后缀了。

  w这个限制怎么办?

  我们在字典树上每一个字符串结尾维护一个vector···这样··时间复杂度是多少?均摊下应该是···可以的···吧?

  

技术分享图片
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 using namespace std;
  7 const int maxn=1000+10;
  8 int ch[maxn*maxn][30],W[maxn];
  9 char s[maxn][maxn];
 10 int val[maxn*maxn];
 11 vector<int>G[maxn*maxn];
 12 int T,n,q,sz;
 13 void insert(char *s,int w){
 14     int len=strlen(s);
 15     int u=0;
 16     for(int i=0;i<len;i++){
 17         int id=s[i]-a;
 18         if(!ch[u][id]){
 19             ch[u][id]=++sz;
 20         }
 21         u=ch[u][id];
 22     }
 23     G[u].push_back(w);
 24     return ;
 25 }
 26 void tra(int u){
 27   /*  if(G[u].size()!=0){
 28         for(int i=0;i<G[u].size();i++){
 29             printf("%d ",G[u][i]);
 30         }
 31         return;
 32     }*/
 33     for(int i=0;i<26;i++){
 34         if(ch[u][i]){
 35           printf("%c",i+a);
 36           tra(ch[u][i]);
 37         }
 38     }
 39     return;
 40 }
 41 int ans;
 42 void check(int u,int k){
 43     if(G[u].size()){
 44         for(int i=0;i<G[u].size();i++){
 45             if(W[G[u][i]]<=W[k]){
 46                 ans++;
 47             }
 48         }
 49     }
 50     for(int i=0;i<26;i++){
 51         if(ch[u][i])
 52             check(ch[u][i],k);
 53     }
 54     return;
 55 }
 56 void solve(int k){
 57     int u=0;
 58     ans=0;
 59     for(int i=strlen(s[k])-1;i>=0;i--){
 60         int id=s[k][i]-a;
 61         if(!ch[u][id]){
 62             return ;
 63         }
 64         u=ch[u][id];
 65     }
 66     check(u,k);
 67     return ;
 68 }
 69 int main(){
 70     scanf("%d",&T);
 71     for(int t=1;t<=T;t++){
 72         scanf("%d",&n);
 73         for(int i=0;i<=1000*1000;i++)G[i].clear();
 74         memset(val,0,sizeof(val));
 75         memset(ch,0,sizeof(ch));
 76         sz=0;
 77         char s1[maxn];
 78         int x;
 79         for(int i=1;i<=n;i++){
 80             scanf("%s%d",s[i],&W[i]);
 81             for(int j=0;j<strlen(s[i]);j++){
 82                 s1[j]=s[i][strlen(s[i])-1-j];
 83             }
 84             s1[strlen(s[i])]=\0;
 85             insert(s1,i);
 86         }
 87        // tra(0);
 88 
 89        scanf("%d",&q);
 90        for(int i=1;i<=q;i++){
 91             int opt;
 92             scanf("%d",&opt);
 93             if(opt==1){
 94                 int x,y;
 95                 scanf("%d%d",&x,&y);
 96                 W[x]=y;
 97             }else if(opt==2){
 98                 int x;
 99                 scanf("%d",&x);
100                 solve(x);
101                 printf("%d\n",ans);
102             }
103        }
104     }
105 return 0;
106 }
View Code

 

【FZU2280】Magic

标签:长度   print   fzu   lap   个数   操作   img   splay   后缀数组   

原文地址:https://www.cnblogs.com/LQLlulu/p/8955376.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!