FZU 2280 Magic
来源:互联网 发布:怎样看龙虎榜数据 编辑:程序博客网 时间:2024/06/04 23:24
给定n个字符串,每个字符串一个价值wi,询问
1 更改某个串的价值
2 查询以第x个串为后缀且价值小等于x串的字符串个数
字符串个数 n<=1000
查询数 q<=80000
分析:根据字符串倒序构建字典树,那么对于某个字符串,以它为后缀的字符串在该字典树中成为了它的子树。然后根据字典树构建dfs序,查询相当于dfs序的区间查询。
算法一: 使用hash预处理出树,然后构建dfs序,分块进行查询和更新。
hash预处理n^2,查询sqrt(n),更新sqrt(n),总时间复杂度:O(q*sqrt(n))
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#define pri 233#define M 1000000007typedef long long ll;using namespace std;struct BlockQuery{int num[35][35][35];int block,cnt;int digit[1010];BlockQuery(int n){int i=1;for (;i*i<n;i++);block=i;cnt=(n-1)/block+1;memset(num,0,sizeof(num));}void add(int pos,int val,int f){int loc=pos/block;int valsq = val/33;digit[pos] = val;for (int i=valsq+1;i<=34;i++)num[loc][i][34] += f;int mval = val%33;for (int i=mval;i<=34;i++)num[loc][valsq][i] += f;}int getLeq(int l,int r,int val){int lb=l/block,rb=r/block;int lbr = lb*block+block-1;int sum=0;if (lb!=rb){for (int i=l;i<=lbr;i++)sum+= (digit[i]<=val)?1:0;for (int i=rb*block;i<=r;i++)sum+= (digit[i]<=val)?1:0;for (int i=lb+1;i<rb;i++){int valsq = val/33;if (valsq>0)sum+= num[i][valsq-1][34];sum+= num[i][valsq][val%33];}}else{for (int i=l;i<=r;i++)sum += digit[i]<=val?1:0;}return sum;}};char st[1010];int l[1010],r[1010];struct node{char st[1010];int hash[1010];int len,id,w,color;} a[1010];bool cmp0(const node &a,const node &b){return a.len>b.len;}int powt[1010];int getHashValue(int *h,int l,int r){return (h[r]-(ll)h[l-1]*powt[r-l+1]%M+M)%M;}int tot,Link[1010];struct node2{int v,next;}edge[10100];void addEdge(int x,int y){tot++;edge[tot].v=y;edge[tot].next=Link[x];Link[x]=tot;}bool vis[1010];int tim;int L[1010],R[1010],Loc[1010];void dfs(int x){vis[x]=true;tim++;Loc[a[x].id]=L[a[x].id]=tim;for (int p=Link[x];p;p=edge[p].next)dfs(edge[p].v);R[a[x].id]=tim;}int main(){powt[0]=1;for (int i=1;i<1010;i++)powt[i]=(ll)powt[i-1]*pri%M;int T;scanf("%d",&T);while (T-->0){int n;scanf("%d",&n);BlockQuery bq(n);for (int i=1;i<=n;i++){scanf("%s %d",a[i].st+1,&a[i].w);a[i].id=i;a[i].len=strlen(a[i].st+1);a[i].hash[0]=0;for (int j=1;j<=a[i].len;j++)a[i].hash[j]=((ll)a[i].hash[j-1]*pri+a[i].st[j])%M;}sort(a+1,a+1+n,cmp0);tot=0;memset(Link,0,sizeof(Link));for (int i=1;i<=n;i++){a[i].color = a[i].id;for (int j=i+1;j<=n;j++){if (getHashValue(a[j].hash,1,a[j].len)==getHashValue(a[i].hash,a[i].len-a[j].len+1,a[i].len)){a[i].color = a[j].id;addEdge(j,i);break;}}}tim=0;memset(vis,0,sizeof(vis));for (int i=1;i<=n;i++)if (!vis[i]&&a[i].color==a[i].id)dfs(i);for (int i=1;i<=n;i++)for (int j=n;j>i;j--)if (a[i].len==a[j].len&&a[i].hash[a[i].len]==a[j].hash[a[i].len]){L[a[i].id] = L[a[j].id];R[a[i].id] = R[a[j].id];break;}for (int i=1;i<=n;i++)bq.add(Loc[a[i].id],a[i].w,1);int q,choose,x,y;scanf("%d",&q);for (int i=1;i<=q;i++){scanf("%d",&choose);if (choose==1){scanf("%d%d",&x,&y);bq.add(Loc[x],bq.digit[Loc[x]],-1);bq.add(Loc[x],y,1);}else{scanf("%d",&x);printf("%d\n",bq.getLeq(L[x],R[x],bq.digit[Loc[x]]));}}}return 0;}
算法二: 建立字典树,构建dfs序。
阅读全文
1 0
- FZU 2280 Magic
- Magic FZU
- Magic FZU
- FZU Problem 2280 Magic(Hash)
- (fzu)Problem I Magic(模拟+后缀匹配)
- FZUOJ 2280 Magic
- 【magic】
- magic
- Magic
- magic
- FZU
- FZU
- FZU
- FZU
- FZU
- FZU
- FZU
- FZU
- CSDN中的如何转载博文
- Spring MVC 验证码后台实现验证以及它的安全性
- POSIX多线程程序设计学习篇之二(互斥量)
- Scrapped or attached views may not be recycled
- Linux学习第三十一篇--RAID和LVM
- FZU 2280 Magic
- jAVA 识别有效的IP地址和掩码并进行分类统计
- PHP页面静态化
- lseek函数详解
- 第六章 中断和动态数码管
- 《机器学习实战》学习笔记(二)
- 关于未来几年的发展,闰土有话要说
- sklearn学习:make_multilabel_classification——多标签数据集方法
- 暑期学习记录12