P7735 [NOI2021] 轻重边

· · 题解

题传

树剖不好维护边权,考虑下放到深度深的结点上。

操作一改成:

对于路径 (a, b) 上的所有结点,将其子节点染成轻点,随后将路径上的所有点染成重点,特别地,\text{LCA}(a, b) 为轻点。

拆成两种操作:

  1. 路径染重/轻;

  2. 子节点染轻。

操作顺序为 3(a, b)--4(a, b) -- 3(\text{LCA}(a, b))

操作三一脸树剖的样子,操作四。。

我们考虑再转化一下题意,我们发现,操作 3/4 中处理的关键是 \text {LCA} 与 子节点,想一下,如果只操作一次,那么问题变为?

找到链上有多少颜色相同的点!!1

既然一次操作是 0/1 染色,不妨改为染 时间戳 i 到每个节点上。

操作 1 变成区间覆盖。

操作 2 让我们统计相邻相等的数量,但是 \text{dfs} 序上不一定相邻,怎么办?

不难发现,我们每次查询的区间为 (\text{top}(x), x),也就是说,我们查询的区间最左端就是某颗子树的根节点!!1(这其实就是 \text{dfs} 序的性质)我们只要在查询的时候注意顺序,把对应的区间连上,就珂以统计中间被连上的点是否相同了。

注意多测清空 ,因为这个卡了好久。

Code:

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int mo=19940417;
const int R=20;
inline int read(){
    char ch=getchar();int x=0, f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
namespace Solution{
    const int N=2e5+5;
    int n, m;
    struct node{
        node(){st=ed=len=tag=ans=0;}
        int st, ed, len, tag, ans;
    }d[N*4];
    node add(node a, node b){
        node c;
        c.len=a.len+b.len;
        c.ans=a.ans+b.ans+(a.ed==b.st);
        c.st=a.st, c.ed=b.ed;
        return c;
    }
    int tot, h[N], dfn[N], cnt, top[N], son[N], fa[N], siz[N], dep[N];
    struct Edge{
        int to, nxt;
    }edge[N*2];
    void add(int x, int y){
        edge[++tot].to=y, edge[tot].nxt=h[x];
        h[x]=tot;return ;
    }
    void dfs1(int x, int f){
        siz[x]=1;
        for(int i=h[x]; i; i=edge[i].nxt){
            int to=edge[i].to;if(to==f) continue;
            dep[to]=dep[x]+1, fa[to]=x, dfs1(to, x);
            siz[x]+=siz[to];if(siz[son[x]]<siz[to]) son[x]=to;
        }
        return ;
    }
    void dfs2(int x, int root){
//      printf("`````%d %d\n", x, root);
        top[x]=root, dfn[x]=++cnt;
        if(son[x]) dfs2(son[x], root);
        for(int i=h[x]; i; i=edge[i].nxt){
            int to=edge[i].to;
            if(top[to]) continue;
            dfs2(to, to);
        }
        return ;
    }
    struct SegmentTree{
        #define ls k<<1
        #define rs k<<1|1
        #define mid (l+r>>1)
        void pushup(int k){d[k]=add(d[ls], d[rs]);return ;}
        void upd(int k, int v){
            d[k].ans=d[k].len-1, d[k].st=d[k].ed=v;
            d[k].tag=v;return ;
        }
        void pushdown(int k){
            if(!d[k].tag) return ;
            upd(ls, d[k].tag), upd(rs, d[k].tag);
            d[k].tag=0;
            return ;
        }
        void build(int k, int l, int r){
            d[k].len=r-l+1, d[k].tag=d[k].ans=0;
            if(l==r){d[k].st=d[k].ed=l&r;return ;}
            build(ls, l, mid), build(rs, mid+1, r);
            return pushup(k);
        }
        void change(int k, int l, int r, int x, int y, int v){
            if(x<=l&&r<=y) return upd(k, v);pushdown(k);
            if(x<=mid) change(ls, l, mid, x, y, v);
            if(mid<y) change(rs, mid+1, r, x, y, v);
            return pushup(k);
        }
        node query(int k, int l, int r, int x, int y){
//          printf("%d %d %d %d %d\n", k, l, r, x, y);
            if(x<=l&&r<=y) return d[k];pushdown(k);
            if(y<=mid) return query(ls, l, mid, x, y);
            if(x>mid) return query(rs, mid+1, r, x, y);
            return add(query(ls, l, mid, x, y), query(rs, mid+1, r, x, y));
        }
        #undef ls
        #undef rs
        #undef mid
    }Chtholly;
    void change(int x, int y, int v){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x, y);
            Chtholly.change(1, 1, n, dfn[top[x]], dfn[x], v);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x, y);
        Chtholly.change(1, 1, n, dfn[x], dfn[y], v);
        return ;
    }
    int LCA(int x, int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x, y);
//          printf(">>>%d %d\n", x, y);
            x=fa[top[x]];
        }
        return dep[x]>dep[y]?y:x;
    }
    int query(int x, int f){
        node ret;
        while(top[x]!=top[f]){
            ret=add(Chtholly.query(1, 1, n, dfn[top[x]], dfn[x]), ret);
            x=fa[top[x]];
        }
        return add(Chtholly.query(1, 1, n, dfn[f], dfn[x]), ret).ans;
    }
    int ask(int x, int y){
        int lca=LCA(x, y);//printf("----%d\n", lca);
        return query(x, lca)+query(y, lca);
    }
    signed work(){
        memset(h, 0, sizeof(h)), tot=cnt=0;
        memset(fa, 0, sizeof(fa));
        memset(son, 0, sizeof(son));
        memset(top, 0, sizeof(top));
        memset(dep, 0, sizeof(dep));
        memset(dfn, 0, sizeof(dfn));
        memset(siz, 0, sizeof(siz));
        n=read(), m=read();
        for(int i=1, a, b; i<n; i++)
            a=read(), b=read(), add(a, b), add(b, a);
        dfs1(dep[1]=1, 0), dfs2(1, 1);
        Chtholly.build(1, 1, n);//Chtholly.debug();
//      for(int i=1; i<=n; i++)
//          printf("->%d %d\n", dep[i], fa[i]); 
        for(int i=1; i<=m; i++){
            int opt=read(), x=read(), y=read();
            if(opt&1) change(x, y, i+n);
            else printf("%d\n", ask(x, y));
        }
        return 0;
    }
}
signed main(){
    int T=read();
    while(T--)
        Solution :: work();
    return 0;
}