思路:
先考虑序列上的问题,用线段树记录一个区间的一些最长路径,代码中的字母对表示这两点之间的最长的路径,
∗m
表示若不能到达,从
∗
出发的最长路径(代码中有图)。已知一个长度为
问题在树上就套一个树链剖分,在处理最后
LCA
的部分的时候要注意区间需要翻转(类似[SDOI2011]染色)。
易错点:
1. 树链剖分里面的
x,y
不要交换,最终的答案跟顺序是有关系的。
2. 链剖中记录
x,y
答案的
resx,resy
要注意是否已经有区间,要是没有区间要改当前,可以用bool变量标记,也可以在结构体内部标记是否可以合并。
3. 变量名一定要看好,不要打错,分清
b,d
。
4. 注意特判最后返回的区间
x
<script type="math/tex" id="MathJax-Element-11">x</script>是在左边还是在右边可以调用翻转,避免分类讨论。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 30010;
int n, m;
int head[maxn], to[maxn<<1], nxt[maxn<<1], cnt;
int top[maxn], dep[maxn], son[maxn], sz[maxn], pos[maxn];
int q[maxn], st[maxn], tp, num[maxn], tim, fa[maxn];
bool vis[maxn], wh;
char cv[maxn][3];
void add(int a, int b){nxt[++ cnt] = head[a], to[head[a] = cnt] = b;}
#define mid ((l+r)>>1)
#define lch ((now<<1))
#define rch ((now<<1)|1)
struct node{
int ab, ad, cb, cd, am, cm, bm, dm;
node(){ab = ad = cb = cd = am = cm = bm = dm = 0;}
void init(){ab = ad = cb = cd = am = cm = bm = dm = 0;}
node turn(){swap(ad, cb), swap(am, bm), swap(cm, dm);return *this;}
}T[maxn * 3];
/*
|-----|
| |
| AB |
|-----|
| |
| CD |
|-----|
*/
inline void update(int now, int id){
node &w = T[now]; w.init();
if(cv[id][0] == '#' && cv[id][1] == '.') w.cd = w.dm = w.cm = 1;
if(cv[id][0] == '.' && cv[id][1] == '#') w.ab = w.am = w.bm = 1;
if(cv[id][0] == '.' && cv[id][1] == '.') w.ab = w.cd = 1, w.ad = w.cb = w.cm = w.dm = w.am = w.bm = 2;
}
/*
------------- -------------
| A | B | | A | B |
| | | | | |
|-----------| |-----------|
| C | D | | C | D |
| | | | | |
------------- -------------
*/
inline node merge(node A, node B){
node res;
if(A.ab != 0 && B.ab != 0) res.ab = max(res.ab, A.ab + B.ab);
if(A.ad != 0 && B.cb != 0) res.ab = max(res.ab, A.ad + B.cb);
if(A.cd != 0 && B.cd != 0) res.cd = max(res.cd, A.cd + B.cd);
if(A.cb != 0 && B.ad != 0) res.cd = max(res.cd, A.cb + B.ad);
if(A.ad != 0 && B.cd != 0) res.ad = max(res.ad, A.ad + B.cd);
if(A.ab != 0 && B.ad != 0) res.ad = max(res.ad, A.ab + B.ad);
if(A.cd != 0 && B.cb != 0) res.cb = max(res.cb, A.cd + B.cb);
if(A.cb != 0 && B.ab != 0) res.cb = max(res.cb, A.cb + B.ab);
if(A.am == 0) res.am = 0;
else if(A.ab == 0 && A.ad == 0) res.am = A.am;
else {
if(A.ab != 0) res.am = max(res.am, A.ab + B.am);
if(A.ad != 0) res.am = max(res.am, A.ad + B.cm);
}
if(A.cm == 0) res.cm = 0;
else if(A.cb == 0 && A.cd == 0) res.cm = A.cm;
else {
if(A.cb != 0) res.cm = max(res.cm, A.cb + B.am);
if(A.cd != 0) res.cm = max(res.cm, A.cd + B.cm);
}
if(B.bm == 0) res.bm = 0;
else if(B.ab == 0 && B.cb == 0) res.bm = B.bm;
else{
if(B.ab != 0) res.bm = max(res.bm, B.ab + A.bm);
if(B.cb != 0) res.bm = max(res.bm, B.cb + A.dm);
}
if(B.dm == 0) res.dm = 0;
else if(B.ad == 0 && B.cd == 0) res.dm = B.dm;
else{
if(B.ad != 0) res.dm = max(res.dm, B.ad + A.bm);
if(B.cd != 0) res.dm = max(res.dm, B.cd + A.dm);
}
return res;
}
void build(int now, int l, int r){
if(l == r){update(now, num[l]); return;}
build(lch, l, mid);
build(rch, mid+1, r);
T[now] = merge(T[lch], T[rch]);
}
void modify(int now, int l, int r, int pos){
if(l == r){update(now, num[l]); return;}
if(pos <= mid) modify(lch, l, mid, pos);
else modify(rch, mid+1, r, pos);
T[now] = merge(T[lch], T[rch]);
}
node que(int now, int l, int r, int pos1, int pos2){
if(l == pos1 && r == pos2) return T[now];
if(pos2 <= mid) return que(lch, l, mid, pos1, pos2);
else if(pos1 >= mid+1) return que(rch, mid+1, r, pos1, pos2);
return merge(que(lch, l, mid, pos1, mid), que(rch, mid+1, r, mid+1, pos2));;
}
node resx, resy;
bool usex, usey;
inline void updatex(node tmp){
if(usex == 0) resx = tmp, usex = 1;
else resx = merge(tmp, resx);
}
inline void updatey(node tmp){
if(usey == 0) resy = tmp, usey = 1;
else resy = merge(tmp, resy);
}
node ask(int x, int y){
usex = 0, usey = 0;
while(top[x] != top[y]){
if(dep[top[x]] > dep[top[y]]) updatex(que(1, 1, n, pos[top[x]], pos[x])), x = fa[top[x]];
else updatey(que(1, 1, n, pos[top[y]], pos[y])), y = fa[top[y]];
}
if(dep[x] > dep[y]){
updatex(que(1, 1, n, pos[y], pos[x]));
if(usey == 0) return resx.turn();
resy.turn();
return merge(resy, resx).turn();
}else{
updatey(que(1, 1, n, pos[x], pos[y]));
if(usex == 0) return resy;
resx.turn();
return merge(resx, resy);
}
}
void pre(){
dep[1] = 1;
int l = 1, r = 0; q[++ r] = 1, vis[1] = 1;
while(l <= r){
int x = q[l ++]; sz[x] = 1;
for(int i = head[x]; i; i = nxt[i]){
int u = to[i]; if(vis[u]) continue;
q[++ r] = u, vis[u] = 1;
dep[u] = dep[x] + 1, fa[u] = x;
}
}
for(int i = n; i >= 1; i --){
int x = q[i];
if(fa[x] != 0) sz[fa[x]] += sz[x];
if(sz[son[fa[x]]] < sz[x]) son[fa[x]] = x;
}
st[++ tp] = 1, top[1] = 1;
while(tp){
int x = st[tp --]; pos[x] = ++ tim, num[tim] = x;
for(int i = head[x]; i; i = nxt[i]){
int u = to[i]; if(u == fa[x] || u == son[x]) continue;
st[++ tp] = u, top[u] = u;
}
if(son[x]) st[++ tp] = son[x], top[son[x]] = top[x];
}
build(1, 1, n);
}
char op[3];
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i ++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
}
for(int i = 1; i <= n; i ++) scanf("%s", cv[i]);
pre();
for(int i = 1; i <= m; i ++){
int x, y; scanf("%s", op);
if(op[0] == 'Q'){
scanf("%d%d", &x, &y);
if(cv[x][0] == '#' && cv[x][1] == '#'){printf("0\n"); continue;}
node ans = ask(x, y);
if(ans.ab == 0 && ans.ad == 0 && ans.cb == 0 && ans.cd == 0) printf("%d\n", max(ans.am, ans.cm));
else printf("%d\n", max(max(ans.ab, ans.ad), max(ans.cb, ans.cd)));
}
if(op[0] == 'C'){
int x; scanf("%d", &x);
scanf("%s", cv[x]);
modify(1, 1, n, pos[x]);
}
}
return 0;
}
数据下载
密码: ybe4
对拍器下载
密码: 6r5u