• 前缀查询(维护字典树前缀和)


    题目链接:

    https://ac.nowcoder.com/acm/problem/15706

    题目大意:

    现在需要您来帮忙维护这个名册,支持下列 4 种操作:

    1. 插入新人名 si,声望为 ai
    2. 给定名字前缀 pi 的所有人的声望值变化 di
    3. 查询名字为 sj 村民们的声望值的和(因为会有重名的)
    4. 查询名字前缀为 pj 的声望值的和
    具体思路:
    一开始是这样想的,在线查询转成离线查。把树建完之后,对整个字典树跑一个dfs序。对于操作一,就是简单的字典树赋权值。对于操作二,就是更新以对当前pi结尾的子树整体赋值di*这段区间的val个数。对于操作三,就是单点查询。对于操作四,就是查询以pj节点的子树的权值和。打出来发现了一个致命的问题,因为你已经将整个字典树,在你维护区间和的时候,
    如果这一段本来应该没有值,但是你的字典树中是仍存在的,也就是这一段区间的值本来应该不应该更新还是更新了。把代码贴上吧,说不定啥时候就能改过来了。
    错误代码:
      1 #pragma comment(linker,"/STACK:1024000000,1024000000")
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 # define ll long long
      5 # define inf 0x3f3f3f3f
      6 # define lson l,mid,rt<<1
      7 # define rson mid+1,r,rt<<1|1
      8 const int maxn = 1e5+200;
      9 int ch[maxn][30];
     10 struct node
     11 {
     12     int type,cost;
     13     string str;
     14     node() {}
     15     node(int xx,int yy,string zz){
     16         type=xx,cost=yy,str=zz;
     17     }
     18 } q[maxn];
     19 int tot=0;
     20 void add_trie_build(string str)
     21 {
     22     int p=0;
     23     int len=str.size();
     24     for(int i=0; i<len; i++)
     25     {
     26         int u=str[i]-'a';
     27         if(!ch[p][u])
     28             ch[p][u]=++tot;
     29         p=ch[p][u];
     30     }
     31 }
     32 int L[maxn],R[maxn];
     33 int dfs_ord;
     34 void dfs(int p)
     35 {
     36     L[p]=++dfs_ord;
     37     for(int i=0; i<26; i++)
     38     {
     39         if(!ch[p][i])
     40             continue;
     41         dfs(ch[p][i]);
     42     }
     43     R[p]=dfs_ord;
     44 }
     45 int tree[maxn<<2],lazy[maxn<<2];
     46 void down(int rt)
     47 {
     48     tree[rt<<1]+=lazy[rt];
     49     tree[rt<<1|1]+=lazy[rt];
     50     lazy[rt<<1]+=lazy[rt];
     51     lazy[rt<<1|1]+=lazy[rt];
     52     lazy[rt]=0;
     53 }
     54 void up(int rt)
     55 {
     56     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
     57 }
     58 void update(int l,int r,int rt,int L,int R,int cost)
     59 {
     60     if(L<=l&&R>=r)
     61     {
     62         tree[rt]+=cost;
     63         lazy[rt]+=cost;
     64         return ;
     65     }
     66     int mid=l+r>>1;
     67     down(rt);
     68     if(L<=mid)
     69         update(lson,L,R,cost);
     70     if(R>mid)
     71         update(rson,L,R,cost);
     72     up(rt);
     73 }
     74 int ask(int l,int r,int rt,int L,int R)
     75 {
     76     if(L<=l&&R>=r)
     77     {
     78         return tree[rt];
     79     }
     80     int mid=l+r>>1;
     81     int sum=0;
     82     down(rt);
     83     if(L<=mid)
     84         sum+=ask(lson,L,R);
     85     if(R>mid)
     86         sum+=ask(rson,L,R);
     87     up(rt);
     88     return sum;
     89 }
     90 int val[maxn];
     91 int get_id(string str,int type)
     92 {
     93     int p=0;
     94     int len=str.size();
     95     for(int i=0; i<len; i++)
     96     {
     97         int u=str[i]-'a';
     98         p=ch[p][u];
     99         if(type)val[p]++;
    100     }
    101     return p;
    102 }
    103 void add_trie_update_type1(string str,int cost)
    104 {
    105     int p=get_id(str,1);
    106     update(1,dfs_ord,1,L[p],L[p],cost);
    107 }
    108 void add_trie_update_type2(string str,int cost)
    109 {
    110     int p=get_id(str,0);
    111     update(1,dfs_ord,1,L[p],R[p],cost*val[p]);
    112 }
    113 int solve(string str,int type)
    114 {
    115     int id=get_id(str,0);
    116     if(type==3)
    117     {
    118         return (val[id]>0?1:0)*ask(1,dfs_ord,1,L[id],L[id]);
    119     }
    120     else if(type==4)
    121     {
    122         return (val[id]>0?1:0)*ask(1,dfs_ord,1,L[id],R[id]);
    123     }
    124 }
    125 string str;
    126 vector<int>ans;
    127 int main()
    128 {
    129     ios::sync_with_stdio(false);
    130     int n;
    131     cin>>n;
    132     int type,cost;
    133     for(int i=1; i<=n; i++)
    134     {
    135         cin>>type;
    136         if(type==1)
    137         {
    138             cin>>str>>cost;
    139             add_trie_build(str);
    140             q[i]=node(type,cost,str);
    141         }
    142         else if(type==2)
    143         {
    144             cin>>str>>cost;
    145             q[i]=node(type,cost,str);
    146         }
    147         else if(type==3)
    148         {
    149             cin>>str;
    150             q[i]=node(type,0,str);
    151         }
    152         else if(type==4)
    153         {
    154             cin>>str;
    155             q[i]=node(type,0,str);
    156         }
    157     }
    158     dfs(0);
    159     for(int i=1; i<=n; i++)
    160     {
    161         if(q[i].type==1)
    162         {
    163             add_trie_update_type1(q[i].str,q[i].cost);
    164         }
    165         else if(q[i].type==2)
    166         {
    167             add_trie_update_type2(q[i].str,q[i].cost);
    168         }
    169         else if(q[i].type==3)
    170         {
    171             printf("%d
    ",solve(q[i].str,3));
    172         }
    173         else if(q[i].type==4)
    174         {
    175             printf("%d
    ",solve(q[i].str,4));
    176         }
    177     }
    178     return 0;
    179 }
    View Code
    然后阿刘给我讲了他的做法。
    维护这个字典树的前缀和,w[i]代表在字典树上,编号为i的节点所代表的前缀,包含这个前缀的字符串的总的权值为多少。但是需要考虑到一个问题,在你查询abb的时候,假设之前有一个a已经更新了,然后让你查询abb这个串的权值,这个时候你是需要在树上往后更新的,所以这里需要打一个lazy标记,每次动态更新就好了。
      1 #pragma comment(linker,"/STACK:1024000000,1024000000")
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 # define ll long long
      5 # define inf 0x3f3f3f3f
      6 # define lson l,mid,rt<<1
      7 # define rson mid+1,r,rt<<1|1
      8 # define int ll
      9 const int maxn = 2e5+200;
     10 int ch[maxn][30];
     11 int val[maxn],w[maxn];
     12 int lazy[maxn];
     13 int tot;
     14 void down(int p)
     15 {
     16     for(int i=0; i<26; i++)
     17     {
     18         int u=ch[p][i];
     19         if(!u)
     20             continue;
     21         w[u]+=lazy[p]*val[u];
     22         lazy[u]+=lazy[p];
     23     }
     24     lazy[p]=0;
     25 }
     26 void add_type1(string str,int cost)
     27 {
     28     int p=0;
     29     int len=str.size();
     30     for(int i=0; i<len; i++)
     31     {
     32         int u=str[i]-'a';
     33         if(!ch[p][u])
     34             ch[p][u]=++tot;
     35         p=ch[p][u];
     36         val[p]++;
     37         w[p]+=cost;
     38         down(p);
     39     }
     40 }
     41 void add_type2(string str,int cost)
     42 {
     43     queue<int>q;
     44     while(!q.empty())
     45         q.pop();
     46     int len=str.size();
     47     int p=0;
     48     for(int i=0; i<len; i++)
     49     {
     50         int u=str[i]-'a';
     51         if(!ch[p][u])
     52             ch[p][u]=++tot;
     53         p=ch[p][u];
     54         down(p);
     55         q.push(p);
     56     }
     57     lazy[p]+=cost;
     58     while(!q.empty())
     59     {
     60         int top=q.front();
     61         w[top]+=cost*val[p];
     62         q.pop();
     63     }
     64 }
     65 int ask_type3(string str)
     66 {
     67     int len=str.size();
     68     int p=0;
     69     for(int i=0; i<len; i++)
     70     {
     71         int u=str[i]-'a';
     72         if(!ch[p][u])
     73             ch[p][u]=++tot;
     74         p=ch[p][u];
     75         down(p);
     76     }
     77     int sum=w[p];
     78     for(int i=0; i<26; i++)
     79     {
     80         int u=ch[p][i];
     81         if(!u)
     82             continue;
     83         sum-=w[ch[p][i]];
     84     }
     85     return sum;
     86 }
     87 int ask_type4(string str)
     88 {
     89     int len=str.size();
     90     int p=0;
     91     for(int i=0; i<len; i++)
     92     {
     93         int u=str[i]-'a';
     94         if(!ch[p][u])
     95             ch[p][u]=++tot;
     96         p=ch[p][u];
     97 down(p);
     98     }
     99     return w[p];
    100 }
    101 string str;
    102 signed main()
    103 {
    104     int n,type,cost;
    105     cin>>n;
    106     for(int i=1; i<=n; i++)
    107     {
    108         cin>>type;
    109         if(type==1)
    110         {
    111             cin>>str>>cost;
    112             add_type1(str,cost);
    113         }
    114         else if(type==2)
    115         {
    116             cin>>str>>cost;
    117             add_type2(str,cost);
    118         }
    119         else if(type==3)
    120         {
    121             cin>>str;
    122             cout<<ask_type3(str)<<endl;
    123         }
    124         else if(type==4)
    125         {
    126             cin>>str;
    127             cout<<ask_type4(str)<<endl;
    128         }
    129     }
    130     return 0;
    131 }
  • 相关阅读:
    《算法》C++代码 Floyd
    《算法》C++代码 快速排序
    3-3当访问到一个文件跳转到另一个文件
    分别应用include指令和include动作标识在一个jsp页面中包含一个文件。
    历届试题 蚂蚁感冒
    HDU 2817 A sequence of numbers
    HDU-2018 母牛的故事
    算法提高 复数归一化
    算法提高 十进制数转八进制数
    算法提高 约数个数
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10953601.html
Copyright © 2020-2023  润新知