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序。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 移动流量充错了怎么办 qq充话费等待发货怎么办 qq充值话费没到账怎么办 电信话费冲错了怎么办 微信手机充错话费充空号怎么办 京东地址写错了怎么办 京东售后不退款怎么办 冲了话费不到账怎么办 币安维护充值怎么办 微信话费未到账怎么办 微信话费交错了怎么办 北京移动查话费余额怎么办 淘宝卖家客服无法联系怎么办? 微信支付月限额怎么办 微信超额20万怎么办 微信支付超额了怎么办 微信零钱超额了怎么办 微信的充值冲错了怎么办 有流量还扣话费怎么办 自动取款机充值到电子账户怎么办 淘宝qb充错了怎么办 q币冲错了人家不给怎么办 qq充值话费错号怎么办 qq充错号码了怎么办 qq交话费不到账怎么办 充错手机号码而且是空号怎么办 微信钱包充错话费怎么办 QQ充值话费充到空号了怎么办 给别人充错话费怎么办 用qq交错话费对方是空号怎么办 号码变成空号了怎么办 qq冲流量冲错了怎么办 流量冲错了套餐怎么办 微信流量充错号码怎么办 微信支付不进账怎么办 充话费充不进去怎么办 用支付宝充话费没到账怎么办 支付宝充话费未到账怎么办 话费充了不到账怎么办 转转买家不确认收货怎么办 充话费错了怎么办啊