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\n", query(L, R, l, r)); 159 } 160 } 161 }