分类:Data Structure
Trie Tree
Prefix Tree
[Wannafly挑战赛14 B 前缀查询]
在一个 Minecraft 村庄中,村长有这一本小写字母构成的名册(字符串的表),
每个名字旁边都记录着这位村民的声望值,而且有的村民还和别人同名。
随着时间的推移,因为没有村民死亡,这个名册变得十分大。
现在需要您来帮忙维护这个名册,支持下列 4 种操作:
1. 插入新人名 si,声望为 ai
2. 给定名字前缀 pi 的所有人的声望值变化 di
3. 查询名字为 sj 村民们的声望值的和(因为会有重名的)
4. 查询名字前缀为 pj 的声望值的和
输入描述:
第一行为两个整数 0≤N≤105 0 ≤ N ≤ 10 5 ,表示接下来有 N 个操作;
接下来 N 行,每行输入一个操作,行首为一个整数 1≤oi≤4 1 ≤ o i ≤ 4 ,表示这一行的操作的种类,
那么这一行的操作和格式为:
1. 插入人名,这一行的格式为 1 si ai,其中 |ai| ≤ 10^3
2. 前缀修改声望,这一行的格式为 2 pi di,其中 |di| ≤ 10^3
3. 查询名字的声望和,这一行的格式为 3 sj
4. 查询前缀的声望和,这一行的格式为 4 pj
输入保证插入人名的字符串的长度和小于或等于 105 10 5 ,总的字符串的长度和小于或等于 106 10 6 。
输出描述:
对于每一次询问操作,在一行里面输出答案。
输入
20
1 a -10
1 abcba -9
1 abcbacd 5
4 a
2 a 9
3 aadaa
3 abcbacd
4 a
3 a
2 a 10
3 a
2 a -2
2 d -8
1 ab -2
2 ab -7
1 aadaa -3
4 a
3 abcba
4 a
4 c
输出
-14
0
14
13
-1
9
11
1
11
0
维护前缀???字典树。。。
本题需要进行单点插入、子树(前缀)更新、单点查询、子树(前缀)查询。
对于子树更新操作,需要维护一个懒惰标记。
考虑好细节。
感觉现在脑残加手残的我,写的代码总是有一堆Bug
#include
using namespace std;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
const int inf = 0x3f3f3f3f;
const long long infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
const int MAXL = 100010;
int n;
struct TNode {
long long sum;
long long val;
long long tag;
int cnt;
int same;
int ch[27];
} node[MAXL];
int tot, root;
void init() {
tot = 0;
root = ++ tot;
memset(node, 0, sizeof(node));
}
inline void pushDown(int pos) {
if (!pos || node[pos].tag == 0) return;
for (int j = 0; j < 26; ++j) {
if (node[pos].ch[j] == 0) continue;
node[node[pos].ch[j]].tag += node[pos].tag;
node[node[pos].ch[j]].sum += node[node[pos].ch[j]].cnt * node[pos].tag;
node[node[pos].ch[j]].val += node[node[pos].ch[j]].same * node[pos].tag;
}
node[pos].tag = 0;
}
void insert(char name[], long long val) {
int pos = root;
for (int i = 0; name[i]; ++i) {
pushDown(pos);
int dig = name[i] - 'a';
if (node[pos].ch[dig] == 0) node[pos].ch[dig] = ++ tot;
node[pos].sum += val;
node[pos].cnt += 1;
pos = node[pos].ch[dig];
}
pushDown(pos);
node[pos].sum += val;
node[pos].val += val;
node[pos].cnt += 1;
node[pos].same += 1;
}
void update(char name[], long long val) {
int pos = root;
for (int i = 0; name[i]; ++i) {
int dig = name[i] - 'a';
if (node[pos].ch[dig] == 0) return;
pos = node[pos].ch[dig];
}
long long cnt = node[pos].cnt;
pos = root;
for (int i = 0; name[i]; ++i) {
pushDown(pos);
int dig = name[i] - 'a';
if (node[pos].ch[dig] == 0) return;
node[pos].sum += cnt * val;
pos = node[pos].ch[dig];
}
pushDown(pos);
node[pos].sum += node[pos].cnt * val;
node[pos].val += node[pos].same * val;
node[pos].tag += val;
}
long long query_prefix(char name[]) {
int pos = root;
for (int i = 0; name[i]; ++i) {
pushDown(pos);
int dig = name[i] - 'a';
if (node[pos].ch[dig] == 0) return 0;
pos = node[pos].ch[dig];
}
pushDown(pos);
return node[pos].sum;
}
long long query_name(char name[]) {
int pos = root;
for (int i = 0; name[i]; ++i) {
pushDown(pos);
int dig = name[i] - 'a';
if (node[pos].ch[dig] == 0) return 0;
pos = node[pos].ch[dig];
}
pushDown(pos);
return node[pos].val;
}
void print(int pos, string path) {
debug(path, node[pos].sum, node[pos].val, node[pos].cnt, node[pos].same);
for (int j = 0; j < 26; ++j) {
pushDown(pos);
if (node[pos].ch[j] == 0) continue;
char ch = j + 'a';
print(node[pos].ch[j], path + ch);
}
}
char name[MAXL];
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
while (~scanf("%d", &n)) {
int oper, val;
init();
for (int i = 1; i <= n; ++i) {
scanf("%d", &oper);
if (oper == 1) {
scanf("%s %d", name, &val);
insert(name, val);
// print(root, "");
} else if (oper == 2) {
scanf("%s %d", name, &val);
update(name, val);
// print(root, "");
} else if (oper == 3) {
scanf("%s", name);
long long ans = query_name(name);
printf("%lld\n", ans);
} else {
scanf("%s", name);
long long ans = query_prefix(name);
printf("%lld\n", ans);
}
}
}
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}