FZU2280 Magic-字典树或Hash-第八届福建省大学生程序设计竞赛

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

Catalog

Problem:Portal传送门

 原题目描述在最下面。
 n个字符串且有权值。两种操作,单点修改权值,询问有多少个字符串包含第k个字符串这个后缀且权值小于等于第k个字符串的权值。

Solution:

预处理+hash

很奇怪为什么没有tle,最坏的复杂度明明有6*8e7呀,FZU测评机这么溜的吗????

  • 预处理出n个桶,装有这个字符串位后缀的字符串编号。
  • 每次暴力查询这个桶。后缀的话hash的时候倒着hash取值就行了。

字典树+树状数组

  • 维护n个bit数组,存有此字符串为后缀的字符串的权值位置(权值树状数组???
  • 然后加入字典树的时候记得要从长度短的开始,然后倒着插入。这样就解决了。
  • 然后因为会有重复的字符串,要处理一下,
  • 感觉挺巧妙的,自己体会去吧,欢迎提问。


AC_Code:
Hash
#include<cstdio>
#include<cstring>
#include <vector>
#include<algorithm>
#define lowbit(x) (x)&(-(x))
#define lson rt<<1
#define rson rt<<1|1
#define mme(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int N = 1000+7;
const int MX = 1000+7;
const int MAXM = 3e5+7;
const uLL base = 99959;
const int MOD = 1000000007;
char ar[N][N];
int w[N], n, Len[N];
vector<int> son[N];
uLL hs[N][N], pw[N];
void HASH(){
  pw[0]=1;
  for(int i=0;i<=1000;++i)pw[i]=pw[i-1]*base;
  for(int i=1;i<=n;++i){
    hs[i][0]=0;int len = Len[i];
    for(int j = 1; j <= len; ++j){
      hs[i][j]=(hs[i][j-1]*base+ar[i][len+1-j]-'a');
    }
  }
}
LL get(int k,int l,int r){
  return (hs[k][r] - hs[k][l-1]*pw[r-l+1]);
}
void init(){
  for(int i = 1; i <= n; ++i){
    son[i].push_back(i);
    for(int j = i + 1; j <= n; ++j){
      if(Len[i] == Len[j]&&hs[i][Len[i]] == hs[j][Len[j]]){
        son[i].push_back(j);
        son[j].push_back(i);
      }else if(Len[i] > Len[j]&&hs[j][Len[j]]==get(i,1,Len[j])){
        son[j].push_back(i);
      }else if(Len[j]>Len[i]&&hs[i][Len[i]]==get(j,1,Len[i])){
        son[i].push_back(j);
      }
    }
  }
}
int main(){
  int tim;
  scanf("%d", &tim);
  while(tim--){
    scanf("%d", &n);
    for(int i=1, u; i <= n; ++i){
      son[i].clear();
      scanf("%s%d", ar[i]+1, &u);
      w[i] = u;Len[i]=strlen(ar[i]+1);
    }
    HASH();
    init();
    int m;scanf("%d", &m);
    while(m--){
      int op,x,y;
      scanf("%d%d",&op, &x);
      if(op==1){
        scanf("%d",&y);
        w[x] = y;
      }else{
        int cnt=0;
        for(int i=0;i<son[x].size();++i){
          int v = son[x][i];
          if(w[v]<=w[x])cnt++;
        }
        printf("%d\n", cnt);
      }
    }
  }
  return 0;
}
字典树+树状数组
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x)&(-(x))
#define lson rt<<1
#define rson rt<<1|1
#define mme(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int N = 1000+7;
const int MX = 1000+7;
const int MXM = 3e5+7;
const int MOD = 1000000007;
char ar[N][N];
int w[N], id[N*10], n, bit[N][N];
int Len[N],End[N];
struct lp{
  int id, len;
}cw[N];
struct node{
  int nex[26];
  void init(){
    memset(nex,-1,sizeof(nex));
  }
}tr[MX*10];
int le, root;
void add(int k,int x,int c){
  while(x <= 1000){
    bit[k][x] += c;x += lowbit(x);
  }
}
int query(int k,int x){
  int sum = 0;
  while(x){
    sum += bit[k][x];x -= lowbit(x);
  }
  return sum;
}
void insert(int k, char *s,int slen){
  int now = root;
  for(int i = slen - 1; i >= 0; --i){
    int x = s[i] - 'a';
    if(tr[now].nex[x] == -1){
      tr[le].init();
      tr[now].nex[x] = le++; 
    }
    now = tr[now].nex[x];
    if(id[now]){//id[now]这个字符串是k的后缀
      add(id[now], w[k], 1);
    }
  }
  if(!id[now]){//新字符串??加!
    id[now] = k;
    add(k, w[k], 1);
  }
  End[k]=id[now];
}
void update(int k, char *s, int v,int slen){
  int now = root;
  for(int i = slen - 1;i >= 0; --i){
    int x = s[i] - 'a';
    now = tr[now].nex[x];
    if(id[now]){//换一个权值
      add(id[now], w[k], -1);
      add(id[now], v, 1);
    }
  }
  w[k] = v;
}
bool cmp(const lp &a, const lp &b){
  return a.len < b.len;
}
void Trie_dele(){
  for(int i = 1; i < N; ++i){
    tr[i].init();
  }
}
int main(){
  int tim;
  scanf("%d", &tim);
  while(tim--){
    scanf("%d", &n);
    root = 0;le = 1;tr[0].init();
    mme(id, 0);mme(bit, 0);
    for(int i=1, u; i <= n; ++i){
      scanf("%s%d", ar[i], &u);
      cw[i].id = i; cw[i].len = strlen(ar[i]);
      w[i] = u;Len[i] = cw[i].len;
    }
    sort(cw+1,cw+n+1,cmp);
    for(int i = 1; i <= n; ++i){//按长度插入
      insert(cw[i].id,ar[cw[i].id],cw[i].len);
    }
    int m;
    scanf("%d", &m);
    while(m--){
      int op, k, v;;scanf("%d", &op);
      if(op == 1){
        scanf("%d%d", &k, &v);
        update(k, ar[k], v, Len[k]);
      }else{
        scanf("%d", &k);
        printf("%d\n", query(End[k], w[k]));
      }
    }
    Trie_dele();
  }
  return 0;
}


Problem Description:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值