可爱的树链剖分(染色)

时间:2019-10-28
本文章向大家介绍可爱的树链剖分(染色),主要包括可爱的树链剖分(染色)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

可爱的树链剖分(染色)

这道题 就是 一道 普通的! 树链剖分+线段树覆盖

注意一下两个线段树合并的时候 如果 \(lval(node<<1|1)==rval(node<<1)\) 相当于这两个线段树的相邻的数字数相同的 那么合并时的\(tot\) \(sum\) 应该 --

所以说这道题有什么细节吗 我感觉是没有的 然而我调了一下午+晚上两个小时 (再次感谢人帅心善的kma小哥哥) (话说为什么他有这么多女朋友,而我还是单身呢) 不 我有萌德

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int maxn=1e6+10;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')  f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();};
    return x*f;
}
int n,m,color[maxn],fir[maxn<<1],nxt[maxn<<1],to[maxn<<1],tot,top[maxn];
int size[maxn],son[maxn],fa[maxn],rk[maxn],id[maxn],dep[maxn],times;
char op[3];
struct nodee{
    int l,r,lval,rval,sum,tag;
    #define lval(x) tree[x].lval
    #define rval(x) tree[x].rval
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define sum(x) tree[x].sum
    #define tag(x) tree[x].tag
}tree[maxn<<4];
void add(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
void dfs1(int x){
    dep[x]=dep[fa[x]]+1;size[x]=1;
    for(int i=fir[x];i;i=nxt[i]){
        int y=to[i];if(y==fa[x]) continue;
        fa[y]=x;dfs1(y);size[x]+=size[y];
        if(size[son[x]]<size[y]) son[x]=y;
    }
}
void dfs2(int x,int tp){
    top[x]=tp;id[x]=++times;rk[times]=x;
    if(son[x]) dfs2(son[x],tp);
    for(int i=fir[x];i;i=nxt[i]){
        int y=to[i];if(id[y]) continue;
        dfs2(y,y);
    }
}
void push_up(int node){
    lval(node)=lval(node<<1);rval(node)=rval(node<<1|1);
    sum(node)=sum(node<<1)+sum(node<<1|1);
    if(rval(node<<1)==lval(node<<1|1))  --sum(node);
}
void build(int node,int l,int r){
    l(node)=l;r(node)=r;
    if(l==r){
        lval(node)=rval(node)=color[rk[l]];
        sum(node)=1;return ;
    }
    int mid=l+r>>1;
    build(node<<1,l,mid);build(node<<1|1,mid+1,r);
    push_up(node);
}
void push_down(int node){
    if(tag(node)){
        tag(node<<1)=tag(node<<1|1)=tag(node);
        lval(node<<1)=rval(node<<1)=lval(node<<1|1)=rval(node<<1|1)=tag(node);
        sum(node<<1)=sum(node<<1|1)=1;
        tag(node)=0;
    }
}
void modify(int node,int ql,int qr,int z){
    if(ql<=l(node) && r(node)<=qr){
        sum(node)=1;tag(node)=z;
        lval(node)=z;rval(node)=z;
        return ;
    }
    push_down(node);
    int mid=l(node)+r(node)>>1;
    if(ql<=mid) modify(node<<1,ql,qr,z);
    if(mid<qr) modify(node<<1|1,ql,qr,z);
    push_up(node);
}
void chain_modify(int x,int y,int z){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]){
            x^=y^=x^=y;
        }
        modify(1,id[top[x]],id[x],z);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])   x^=y^=x^=y;
    modify(1,id[y],id[x],z);
    return ;
}
int Rval = 0,Lval = 0,last1 = 0,last2 = 0;
int query(int node,int ql,int qr){
    if(ql==l(node)) Lval=lval(node);
    if(qr==r(node)) Rval=rval(node);
    if(ql<=l(node) && r(node)<=qr){
        return sum(node);
    }
    push_down(node);
    int ans=0,mid=l(node)+r(node)>>1;
    if(ql>mid) ans+=query(node<<1|1,ql,qr);
    else if (qr <= mid) ans += query(node<<1,ql,qr);
    else {
            if(rval(node<<1)==lval(node<<1|1))  ans+=query(node<<1,ql,qr)+query(node<<1|1,ql,qr)-1;
        else ans+=query(node<<1,ql,qr)+query(node<<1|1,ql,qr);
    }
    return ans;
}
int chain_query(int x,int y){
    last1 = 0, last2 = 0, Lval = 0, Rval = 0;
    int tx=top[x],ty=top[y];
    int ans=0;
    while(tx!=ty){
        if(dep[tx]<dep[ty]){
            x^=y^=x^=y;
            tx^=ty^=tx^=ty;
            last1^=last2^=last1^=last2;
        }
        ans+=query(1,id[tx],id[x]);
        if(last1==Rval) --ans;
        last1=Lval;
        x=fa[tx];tx=top[x];
    }
    if(dep[x]<dep[y]){
        x^=y^=x^=y;
        last1^=last2^=last1^=last2;
    }
    ans+=query(1,id[y],id[x]);
    if(Rval==last1) ans--;
    if(Lval==last2) ans--;
    return ans;
}
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)
        color[i]=read();
    for(int i=1,x,y;i<=n-1;i++){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dfs1(1);dfs2(1,1);
    build(1,1,n);
    for(int i=1,x,y,z;i<=m;i++){
        scanf("%s",op + 1);x=read();y=read();
        if(op[1]=='C') {
            z=read();chain_modify(x,y,z);
        }
        if(op[1]=='Q') printf("%lld\n",chain_query(x,y));
    }
    return 0;
}

但是注意一下 在chain_query 和 chain_modify 的时候 最后的判断语句一定不能改方向(为什么呢我不知道) 我好难受啊

原文地址:https://www.cnblogs.com/mendessy/p/11755588.html