2019南京ICPC(重现赛) F - Paper Grading

Posted xwdzuishuai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019南京ICPC(重现赛) F - Paper Grading相关的知识,希望对你有一定的参考价值。

题目链接:https://nanti.jisuanke.com/t/42400

这还是去年去现场赛打的,当时菜的不行,就白给了。最近学了主席树套树状数组,感觉好强的数据结构啊。我们学长说这题挺简单,建字典树dfs序,跑cdq分治就好了(%%%)。本菜鸡发现这题主席树套树状数组也能做。

 

题意:给你n个字符串,m个操作。操作1交换俩个字符串,操作2,给定一个字符串s,数字k, l, r, 求l ~ r与s公共前缀大于等于k的字符串的个数。

 

首先考虑没有修改,那么就只有操作2,设f[i]为第i个字符串结尾的dfn序。把要询问的字符串在字典树里面第k的位置x求出来。那么就变成求in[x]~out[x]中存在的f[l] ~ f[r]数量,考虑是区间询问,所以用主席树。我们在每个in[x]上建值域线段树(1, n)并在i上加1。就可以变成求in[x]~out[x]中存在l~r的数量,很明显的主席树。然后考虑修改,每次修改会把f[i]和f[j]的位置交换,所以就交换了值域i, j。

 

技术图片
  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int N = 2e5 + 10;
  6 
  7 int n, m;
  8 
  9 char s[N];
 10 
 11 int f[N];
 12 
 13 struct Trie{
 14     int son[N][26], idx = 0;
 15     int in[N], out[N], num = 0;
 16     int insert(char *s)
 17     {
 18         int p = 0;
 19         for (int i = 0; s[i]; i ++)
 20         {
 21             int u = s[i] - a;
 22             if(!son[p][u])
 23             son[p][u] = ++ idx;
 24             p = son[p][u];
 25         }
 26         return p;
 27     } 
 28     void dfs(int x)
 29     {
 30         in[x] = ++ num;
 31         for (int i = 0; i < 26; i ++)
 32             if(son[x][i])
 33                 dfs(son[x][i]);
 34         out[x] = num;
 35     }
 36     int find(char* s, int k)
 37     {
 38         int p = 0;
 39         for (int i = 0; i < k; i ++)
 40         {
 41             int u = s[i] - a;
 42             if(!son[p][u])
 43             return -1;
 44             p = son[p][u];
 45         }
 46         return p;
 47     }
 48 }t;
 49 
 50 struct Seg{
 51     int l, r;
 52     int val;
 53 }tr[N * 100];
 54 
 55 int root[N];
 56 int num;
 57 
 58 void build(int &rt, int l, int r)
 59 {
 60     if(!rt)
 61     rt = ++ num;
 62     if(l == r) return ;
 63     int mid = l + r >> 1;
 64     build(tr[rt].l, l, mid);
 65     build(tr[rt].r, mid + 1, r); 
 66 }
 67 
 68 void update(int &p, int x, int c, int l, int r)
 69 {
 70     if(!p) p = ++ num;
 71     tr[p].val += c;
 72     if(l == r) return ;
 73     int mid = l + r >> 1;
 74     if(x <= mid)
 75     update(tr[p].l, x, c, l, mid);
 76     else
 77     update(tr[p].r, x, c, mid + 1,r);
 78 }
 79 
 80 int lowbit(int x)
 81 {
 82     return x & (-x);
 83 }
 84 void update(int x, int y, int c)
 85 {
 86     for (; x < N; x += lowbit(x))
 87     {
 88         update(root[x], y, c, 1, n);
 89     }
 90 }
 91 
 92 int query(int p, int L, int R, int l, int r)
 93 {
 94     if(L <= l && R >= r)
 95     {
 96         return tr[p].val;
 97      } 
 98      int mid = l + r >> 1;
 99         int res = 0;
100     if(L <= mid)
101     res += query(tr[p].l, L, R, l, mid);
102     if(R >  mid)
103     res += query(tr[p].r, L, R, mid + 1, r);
104     return res;     
105 }
106 
107 int query(int x, int y, int L, int R)
108 {
109     int res = 0;
110     for (; y; y -= lowbit(y))
111         res += query(root[y], L, R, 1, n);
112     for (; x; x -= lowbit(x))
113         res -= query(root[x], L, R, 1, n);
114     return res;
115 }
116 
117 int main()
118 {
119     scanf("%d%d", &n, &m);
120     for (int i = 1; i <= n; i ++)
121     {
122         scanf("%s",s);
123         f[i] = t.insert(s);
124     }
125     t.dfs(0);
126     build(root[0], 1, n);
127     for (int i = 1; i <= n; i ++)
128     {
129         update(t.in[f[i]], i, 1);
130         f[i] = t.in[f[i]];
131     }
132     while(m --)
133     {
134         int op;
135         scanf("%d", &op);
136         if(op == 1)
137         {
138             int l, r;
139             scanf("%d%d", &l, &r);
140             update(f[l], l, -1);
141             update(f[r], r, -1);
142             swap(f[l], f[r]);
143             update(f[l], l, 1);
144             update(f[r], r, 1);
145         }
146         else
147         {
148             int k, l, r;
149             scanf("%s%d%d%d", s, &k, &l, &r);
150             int pos = t.find(s, k);
151             if(pos == -1)
152             {
153                 puts("0");
154                 continue;
155             }
156             int L = t.in[pos] - 1, R = t.out[pos];
157         //    cout << L << " " << R << endl;
158             printf("%d
", query(L, R, l, r));
159         }
160     }
161 } 
View Code

 

以上是关于2019南京ICPC(重现赛) F - Paper Grading的主要内容,如果未能解决你的问题,请参考以下文章

ICPC2019 亚洲区域赛 南京站

2018ICPC南京赛区网络赛J Sum(素数筛+找规律)

2019ICPC南京网络赛A题 The beautiful values of the palace(三维偏序)

2019icpc南京网络赛 A 主席树

ICPC亚洲区域赛(南京) M.Monster Hunter(树形dp)

2019ACM-ICPC南京网络赛Holy Grail (SPFA模板题)