[Problem]
bzoj3531
[Solution]
The data range makes me think of tree chain partition. However, you cannot deal with 10^5 types of different colors at the same time.
You can figure out that each query only works with those which have the same color with it. Therefore, we can solve the problem offline.
We attach each operation to the color related to it by the order of time. Then, for each color, we only work on those which are related to it.
Although it's a little complex to code it, it's not hard to use. I only spent 40 minutes on coding && debug. (just debug according to the sample I/O)
[Code]
It's kind of long, and looks very ugly, although it ranked 3 on BZOJ.
#define PROC "travel"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <memory.h>
#include <vector>
#include <algorithm>
using namespace std;
struct edge {
int t;
edge *next;
};
struct seg {
int l, r, s, m;
seg *ls, *rs;
};
struct query {
int x, y, ans, vo;
char o[5];
};
int nextInt() {
int d, s = 0;
do
d = getchar();
while (!isdigit(d));
do
s = s * 10 + d - 48, d = getchar();
while (isdigit(d));
return s;
}
const int maxn = 100010;
const int randSeed = 2189472;
vector <int> cq[maxn], o[maxn];
int n, m, v0[maxn], vn[maxn], c0[maxn], cn[maxn], cm;
int tc, fc[maxn], cl[maxn], ch[maxn], d[maxn], fa[maxn], sz[maxn];
seg *rt[maxn], *sp;
edge *head[maxn], *ep;
query q[maxn];
inline void addEdge(int u, int v) {
ep-> t = v;
ep-> next = head[u];
head[u] = ep ++;
}
#define mid(p) ((p->l+p->r)>>1)
#define update(p) {\
p-> s = p-> ls-> s + p-> rs-> s;\
p-> m = max(p-> ls-> m, p-> rs-> m);\
}
seg *sgtMake(int l, int r) {
seg *p = sp ++;
p-> l = l;
p-> r = r;
p-> s = 0;
p-> m = 0;
if (l + 1 < r) {
p-> ls = sgtMake(l, mid(p));
p-> rs = sgtMake(mid(p), r);
}
return p;
}
void sgtChg(seg *p, int p0, int v0) {
if (p-> l + 1 == p-> r) {
p-> s = v0;
p-> m = v0;
}
else {
if (p0 < mid(p))
sgtChg(p-> ls, p0, v0);
else
sgtChg(p-> rs, p0, v0);
update(p);
}
}
int sgtSum(seg *p, int l, int r) {
if (p-> l == l && p-> r == r)
return p-> s;
else if (r <= mid(p))
return sgtSum(p-> ls, l, r);
else if (l >= mid(p))
return sgtSum(p-> rs, l, r);
else
return sgtSum(p-> ls, l, mid(p)) + sgtSum(p-> rs, mid(p), r);
}
int sgtMax(seg *p, int l, int r) {
if (p-> l == l && p-> r == r)
return p-> m;
else if (r <= mid(p))
return sgtMax(p-> ls, l, r);
else if (l >= mid(p))
return sgtMax(p-> rs, l, r);
else
return max(sgtMax(p-> ls, l, mid(p)), sgtMax(p-> rs, mid(p), r));
}
void divide(int p0) {
static int q[maxn];
int hd = 0, tl = 1;
memset(d, 0, sizeof(d));
q[hd] = p0;
d[p0] = 1;
fa[p0] = 0;
while (hd < tl) {
int p = q[hd ++];
for (edge *g = head[p]; g; g = g-> next)
if (!d[g-> t]) {
d[g-> t] = d[p] + 1;
fa[g-> t] = p;
q[tl ++] = g-> t;
}
}
tc = 0;
for (int i = tl - 1; i >= 0; i --) {
int p = q[i], fp = -1;
sz[p] = 1;
for (edge *g = head[p]; g; g = g-> next)
if (g-> t != fa[p]) {
sz[p] += sz[g-> t];
if (fp == -1 || sz[g-> t] > sz[fp])
fp = g-> t;
}
if (fp == -1) {
fc[p] = tc ++;
ch[fc[p]] = p;
cl[fc[p]] = 1;
}
else {
fc[p] = fc[fp];
ch[fc[p]] = p;
cl[fc[p]] ++;
}
}
for (int i = 0; i < tc; i ++)
rt[i] = sgtMake(0, cl[i]);
}
inline void chgNode(int p, int v) {
sgtChg(rt[fc[p]], d[p] - d[ch[fc[p]]], v);
}
int LCA(int p, int q) {
while (fc[p] != fc[q])
if (d[ch[fc[p]]] > d[ch[fc[q]]])
p = fa[ch[fc[p]]];
else
q = fa[ch[fc[q]]];
if (d[p] < d[q])
return p;
else
return q;
}
int pathSum(int p, int a) {
int s = 0;
while (fc[p] != fc[a]) {
s += sgtSum(rt[fc[p]], 0, d[p] - d[ch[fc[p]]] + 1);
p = fa[ch[fc[p]]];
}
s += sgtSum(rt[fc[p]], d[a] - d[ch[fc[a]]], d[p] - d[ch[fc[p]]] + 1);
return s;
}
int pathMax(int p, int a) {
int m = 0;
while (fc[p] != fc[a]) {
m = max(m, sgtMax(rt[fc[p]], 0 ,d[p] - d[ch[fc[p]]] + 1));
p = fa[ch[fc[p]]];
}
m = max(m, sgtMax(rt[fc[p]], d[a] - d[ch[fc[a]]], d[p] - d[ch[fc[p]]] + 1));
return m;
}
void dealQuery(query *q, int nc) {
if (q-> o[0] == 'C') {
if (q-> o[1] == 'C') {
if (q-> y == nc)
chgNode(q-> x, q-> vo);
else
chgNode(q-> x, 0);
}
else
chgNode(q-> x, q-> y);
}
else {
int a = LCA(q-> x, q-> y);
if (q-> o[1] == 'S')
q-> ans = pathSum(q-> x, a) + pathSum(q-> y, a) - pathSum(a, a);
else
q-> ans = max(pathMax(q-> x, a), pathMax(q-> y, a));
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen(PROC ".in", "r", stdin);
freopen(PROC ".out", "w", stdout);
#endif
cm = 0;
memset(head, 0, sizeof(head));
ep = new edge[maxn * 2];
sp = new seg[maxn * 4];
n = nextInt();
m = nextInt();
for (int i = 1; i <= n; i ++) {
v0[i] = nextInt();
c0[i] = nextInt();
cn[i] = c0[i];
vn[i] = v0[i];
o[c0[i]]. push_back(i);
cm = max(cm, c0[i]);
}
for (int i = 0; i < n - 1; i ++) {
int u = nextInt(), v = nextInt();
addEdge(u, v);
addEdge(v, u);
}
for (int i = 0; i < m; i ++) {
char opt[5];
scanf("\n%s", opt);
q[i]. x = nextInt();
q[i]. y = nextInt();
strcpy(q[i]. o, opt);
if (opt[0] == 'C') {
if (opt[1] == 'C') {
if (cn[q[i]. x] != q[i]. y) {
cq[cn[q[i]. x]]. push_back(i);
cq[q[i]. y]. push_back(i);
cn[q[i]. x] = q[i]. y;
q[i]. vo = vn[q[i]. x];
cm = max(cm, q[i]. y);
}
}
else {
cq[cn[q[i]. x]]. push_back(i);
vn[q[i]. x] = q[i]. y;
}
}
else
cq[cn[q[i]. x]]. push_back(i);
}
divide(randSeed % n + 1);
for (int i = 0; i <= cm; i ++) {
for (vector <int> :: iterator j = o[i]. begin(); j != o[i]. end(); j ++)
chgNode(*j, v0[*j]);
for (vector <int> :: iterator j = cq[i]. begin(); j != cq[i]. end(); j ++)
dealQuery(q + *j, i);
for (vector <int> :: iterator j = o[i]. begin(); j != o[i]. end(); j ++)
chgNode(*j, 0);
for (vector <int> :: iterator j = cq[i]. begin(); j != cq[i]. end(); j ++)
if (q[*j]. o[0] == 'C')
chgNode(q[*j]. x, 0);
}
for (int i = 0; i < m; i ++)
if (q[i]. o[0] == 'Q')
printf("%d\n", q[i]. ans);
}