[COJ2201][KOJ0223][KOJ0250]花园

试题描述

小奇的花园有n个温室,标号为1到n,温室以及以及温室间的双向道路形成一棵树。

每个温室都种植着一种花,随着季节的变换,温室里的花的种类也在不断发生着变化。

小奇想知道从温室x走到温室y的路径中(包括两个端点),第t种花出现的次数。

输入

第一行为两个整数n,q,表示温室的数目和操作的数目。

第二行有n个整数T1,T2…Tn其中Ti表示温室i中的花的种类。

接下来n-1行,每个两个整数x, y,表示温室x和y之间有一条双向道路。

接下来q行,表示q个操作,分别为以下两种形式之一:

• C x t 表示在温室x中的花的种类变为t。

• Q x y t 表示询问温室x走到温室y的路径中(包括两个端点),第t种花出现的次数。

为了体现在线操作,输入数据中的每个操作的参数都进行了加密。记最后一次询问的答案为anslast(一开始设anslast为0),下次读入中的x,y,t均需要异或上anslast以得到真实值,在C/C++中异或为ˆ运算符,在pascal中为xor运算符。

输出

输出q行,每行一个正整数表示该次询问答案。

输入示例


Q
C
Q
C
Q
C
Q
Q

输出示例

数据规模及约定

对于30%的数据,有n <= 1000, q <= 2000。

对于50%的数据,有n <= 10000, q <= 20000。

对于100%的数据,有n <= 100000, q <= 200000,0 <= T < 2^31。

题解

解法一:树链剖分套线段树套 treap。T 飞~~

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define maxnode 7600010 struct Node {
int v, r, siz;
Node() {}
Node(int _, int __): v(_), r(__) {}
} ns[maxnode];
int ToT, fa[maxnode], ch[2][maxnode], rec;
int getnode() {
if(rec) {
int tmp = rec; rec = 0;
fa[tmp] = ch[0][tmp] = ch[1][tmp] = 0;
return tmp;
}
return ++ToT;
}
void maintain(int o) {
if(!o) return ;
ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].siz += ns[ch[i][o]].siz;
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
void insert(int& o, int v) {
if(!o) {
ns[o = getnode()] = Node(v, rand());
return maintain(o);
}
bool d = v > ns[o].v;
insert(ch[d][o], v); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
void del(int& o, int v) {
if(!o) return ;
if(ns[o].v == v) {
if(!ch[0][o] && !ch[1][o]) rec = o, o = 0;
else if(!ch[0][o]) {
int t = ch[1][o]; fa[t] = fa[o]; rec = o; o = t;
}
else if(!ch[1][o]) {
int t = ch[0][o]; fa[t] = fa[o]; rec = o; o = t;
}
else {
bool d = ns[ch[1][o]].r > ns[ch[0][o]].r;
int t = ch[d][o]; rotate(t); o = t;
del(ch[d^1][o], v);
}
}
else {
bool d = v > ns[o].v;
del(ch[d][o], v);
}
return maintain(o);
}
int findlow(int o, int v) {
if(!o) return 0;
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(v > ns[o].v) return ls + 1 + findlow(ch[1][o], v);
return findlow(ch[0][o], v);
}
int findupp(int o, int v) {
if(!o) return 0;
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(v >= ns[o].v) return ls + 1 + findupp(ch[1][o], v);
return findupp(ch[0][o], v);
} int rt[maxn<<2], val[maxn];
void Add(int L, int R, int o, int x) {
insert(rt[o], val[x]);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(x <= M) return Add(L, M, lc, x);
return Add(M+1, R, rc, x);
}
void Upd(int L, int R, int o, int x, int v) {
del(rt[o], val[x]); insert(rt[o], v);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(x <= M) return Upd(L, M, lc, x, v);
return Upd(M+1, R, rc, x, v);
}
int Que(int L, int R, int o, int ql, int qr, int v) {
if(ql <= L && R <= qr) return findupp(rt[o], v) - findlow(rt[o], v);
int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = 0;
if(ql <= M) ans += Que(L, M, lc, ql, qr, v);
if(qr > M) ans += Que(M+1, R, rc, ql, qr, v);
return ans;
} int n, m, head[maxn], next[maxm], to[maxm];
void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
}
int pa[maxn], son[maxn], dep[maxn], siz[maxn], top[maxn], W[maxn], ww;
void build(int u) {
siz[u] = 1;
for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u]) {
pa[to[e]] = u;
dep[to[e]] = dep[u] + 1;
build(to[e]);
siz[u] += siz[to[e]];
if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
}
return ;
}
void gett(int u, int tp) {
W[u] = ++ww; top[u] = tp;
if(son[u]) gett(son[u], tp);
for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u] && to[e] != son[u])
gett(to[e], to[e]);
return ;
}
int query(int a, int b, int v) {
int f1 = top[a], f2 = top[b], ans = 0;
while(f1 != f2) {
if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
int tmp = Que(1, n, 1, W[f1], W[a], v);
ans += Que(1, n, 1, W[f1], W[a], v);
a = pa[f1]; f1 = top[a];
}
if(dep[a] < dep[b]) swap(a, b);
int tmp = Que(1, n, 1, W[b], W[a], v);
ans += Que(1, n, 1, W[b], W[a], v);
return ans;
} int T[maxn];
int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) T[i] = read();
for(int i = 1; i < n; i++) {
int a = read(), b = read();
AddEdge(a, b);
}
build(1); gett(1, 1);
for(int i = 1; i <= n; i++) val[W[i]] = T[i];
for(int i = 1; i <= n; i++) Add(1, n, 1, i);
int lst = 0;
while(q--) {
char tp[2];
scanf("%s", tp);
if(tp[0] == 'C') {
int x = read() ^ lst, t = read() ^ lst;
Upd(1, n, 1, W[x], t); val[W[x]] = t;
}
if(tp[0] == 'Q') {
int a = read() ^ lst, b = read() ^ lst, t = read() ^ lst;
lst = query(a, b, t);
printf("%d\n", lst);
}
} return 0;
}

解法二:对于每一种颜色建一颗线段树,求一边 dfs 序把点修改链上询问转化成区间修改点询问的问题,线段树动态开节点防止爆炸。(别用 map 用 hash……)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define maxnode 10000010
int n, m, head[maxn], next[maxm], to[maxm], T[maxn]; #define MOD 233333
int Th, hd[MOD], nxt[maxn*3], Val[maxn*3];
int Find(int x) {
int v = (x % MOD + MOD) % MOD;
for(int e = hd[v]; e; e = nxt[e]) if(Val[e] == x) return e;
return 0;
}
void insert(int x) {
int v = (x % MOD + MOD) % MOD;
Val[++Th] = x; nxt[Th] = hd[v]; hd[v] = Th;
return ;
} void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
}
int fa[maxn], son[maxn], siz[maxn], dep[maxn], top[maxn], W[maxn], ww, dl[maxn], dr[maxn];
void build(int u) {
siz[u] = 1;
for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u]) {
fa[to[e]] = u;
dep[to[e]] = dep[u] + 1;
build(to[e]);
siz[u] += siz[to[e]];
if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
}
return ;
}
void gett(int u, int tp) {
dl[u] = W[u] = ++ww; top[u] = tp;
if(son[u]) gett(son[u], tp);
for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u] && to[e] != son[u])
gett(to[e], to[e]);
dr[u] = ww;
return ;
}
int lca(int a, int b) {
int f1 = top[a], f2 = top[b];
while(f1 != f2) {
if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
a = fa[f1]; f1 = top[a];
}
return dep[a] < dep[b] ? a : b;
} int ToT, rt[maxn*3], lc[maxnode], rc[maxnode], S[maxnode], addv[maxnode];
void pushdown(int o, int L, int R) {
if(!addv[o]) return ;
S[o] += addv[o];
if(L < R) {
if(!lc[o]) lc[o] = ++ToT;
if(!rc[o]) rc[o] = ++ToT;
addv[lc[o]] += addv[o];
addv[rc[o]] += addv[o];
}
addv[o] = 0;
return ;
}
void update(int& o, int L, int R, int ql, int qr, int v) {
if(!o) o = ++ToT;
pushdown(o, L, R);
if(ql <= L && R <= qr) addv[o] += v;
else {
int M = L + R >> 1;
if(ql <= M) update(lc[o], L, M, ql, qr, v);
if(qr > M) update(rc[o], M+1, R, ql, qr, v);
}
return ;
}
int query(int o, int L, int R, int x) {
if(!x || !o) return 0;
pushdown(o, L, R);
if(L == R) return S[o];
int M = L + R >> 1;
if(x <= M) return query(lc[o], L, M, x);
return query(rc[o], M+1, R, x);
} int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) {
T[i] = read();
if(!Find(T[i])) insert(T[i]);
}
// for(int i = 1; i <= n; i++) printf("%d%c", Find(T[i]), i < n ? ' ' : '\n');
for(int i = 1; i < n; i++) {
int a = read(), b = read();
AddEdge(a, b);
}
build(1); gett(1, 1);
// for(int i = 1; i <= n; i++) printf("%d: %d %d\n", i, dl[i], dr[i]);
for(int i = 1; i <= n; i++) update(rt[Find(T[i])], 1, n, dl[i], dr[i], 1);
int lst = 0;
while(q--) {
char Tp[2]; scanf("%s", Tp);
if(Tp[0] == 'C') {
int x = read() ^ lst, t = read() ^ lst;
update(rt[Find(T[x])], 1, n, dl[x], dr[x], -1);
T[x] = t; if(!Find(t)) insert(t);
update(rt[Find(t)], 1, n, dl[x], dr[x], 1);
}
if(Tp[0] == 'Q') {
int a = read() ^ lst, b = read() ^ lst, t = rt[Find(read()^lst)], c = lca(a, b);
int A = query(t, 1, n, W[a]), B = query(t, 1, n, W[b]), C = query(t, 1, n, W[c]), fC = query(t, 1, n, W[fa[c]]);
// printf("%d %d %d(%d) %d(%d)\n", A, B, C, c, fC, fa[c]);
lst = A + B - C - fC;
printf("%d\n", lst);
}
} return 0;
}
05-02 01:31