【BZOJ 2325】[ZJOI2011]道馆之战

思路:

先考虑序列上的问题,用线段树记录一个区间的一些最长路径,代码中的字母对表示这两点之间的最长的路径, m 表示若不能到达,从 出发的最长路径(代码中有图)。已知一个长度为1的区间,填充信息在 update() 。合并两个区间,在 merge()
问题在树上就套一个树链剖分,在处理最后 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值