[SDOI2011]染色 (线段树维护子段问题+树剖)

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2011]染色 (线段树维护子段问题+树剖)相关的知识,希望对你有一定的参考价值。

题意:
给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种:

1.将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c。
2.询问节点 a 到节点 b 的路径上的颜色段数量。

颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:11、222、1。

题解:
树剖+线段树维护区间子段和问题。
如果在在单独的线段树上操作的话,难度还不是特别高,这个题因为转移到了树上去,树剖的本质是把线段树的区间给分成了好几段,所以我们在经过树上路径的时候,衔接位置要特别注意。

一个小细节的地方。!!!
由代码可见,这是两种不同的写法;
出锅的原因:未考虑清楚L1由x决定,那么L2应由x匹配,L2则与y;
在这里插入图片描述

if(dep[x]<dep[y]) 
swap(x,y),swap(ansl,ansr);
ans+=query(1,id[y],id[x],id[y],id[x]);
if(Rc==ansl) ans--;
if(Lc==ansr) ans--;
/*
if(dep[x]>dep[y])
swap(x,y),swap(ansl,ansr);
ans+=query(1,id[x],id[y],id[x],id[y]);
if(Lc==ansl) ans--;
if(Rc==ansr) ans--;*/

代码:

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
//#define int long long
const int maxn=1e5+10;
#define endl '\\n'

struct node{
    int to,next;
}edge[maxn*2];

int a[maxn],head[maxn*2],dep[maxn];
int f[maxn],sz[maxn],son[maxn];
int tot;int n,m;
void add(int u,int v){
    edge[tot].to=v,edge[tot].next=head[u];
    head[u]=tot++;
    edge[tot].to=u,edge[tot].next=head[v];
    head[v]=tot++;
}

void dfs1(int x,int fa){
    f[x]=fa;
    dep[x]=dep[fa]+1;
    sz[x]=1;
    for(int i=head[x];~i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa) continue;
        dfs1(to,x);
        sz[x]+=sz[to];
        if(sz[to]>sz[son[x]]) son[x]=to;
    }
}

int dfn[maxn],top[maxn],w[maxn];
int cnt;
void dfs2(int x,int t){
    dfn[x]=++cnt;
    top[x]=t;
    w[cnt]=a[x];
    if(!son[x]) return ;
    dfs2(son[x],t);
    for(int i=head[x];~i;i=edge[i].next){
        int to=edge[i].to;
        if(to==f[x]||to==son[x]) continue;
        dfs2(to,to);
    }
}
int lcol[maxn*4],rcol[maxn*4],tree[maxn*4];

void push_up(int node){
    if(rcol[node*2]==lcol[node*2+1]){
        tree[node]=tree[node*2]+tree[node*2+1]-1;
    }
    else tree[node]=tree[node*2]+tree[node*2+1];
    lcol[node]=lcol[node*2];
    rcol[node]=rcol[node*2+1];
}
void build(int node,int start,int ends){
    if(start==ends){
        tree[node]=1;
        lcol[node]=rcol[node]=w[start];
        return ;
    }
    int mid=(start+ends)/2;
    build(node*2,start,mid);
    build(node*2+1,mid+1,ends);
    push_up(node);
}
int lazy[maxn*4];
void push_down(int node){
    if(lazy[node]!=0){
        lazy[node*2]=lazy[node*2+1]=lazy[node];
        lcol[node*2]=rcol[node*2]=lcol[node*2+1]=rcol[node*2+1]=lazy[node];
        tree[node*2]=tree[node*2+1]=1;
        lazy[node]=0;
    }
}

void update(int node,int start,int ends,int l,int r,int val){
    if(l<=start&&ends<=r){
        tree[node]=1;
        lcol[node]=rcol[node]=lazy[node]=val;
        return ;
    }
    int mid=(start+ends)/2;
    push_down(node);
    if(l<=mid) update(node*2,start,mid,l,r,val);
    if(mid<r) update(node*2+1,mid+1,ends,l,r,val);
    push_up(node);
}

int querycnt(int node,int start,int ends,int l,int r,int &ansl,int &ansr){
    if(l<=start&&ends<=r){
        if(l==start) ansl=lcol[node];
        if(r==ends) ansr=rcol[node];
        return tree[node];
    }
    int mid=(start+ends)/2;
    push_down(node);
    int res=0;
    if(l<=mid) res+=querycnt(node*2,start,mid,l,r,ansl,ansr);
    if(mid<r) res+=querycnt(node*2+1,mid+1,ends,l,r,ansl,ansr);
    if(rcol[node*2]==lcol[node*2+1]&&l<=mid&&mid<r) return res-1;
    else  return res;
}

//int querycol(int node,int start,int ends,int pos){
//    if(start==ends) return lcol[node];
//    int mid=(start+ends)/2;
//    push_down(node);
//    if(pos<=start) return querycol(node*2,start,mid,pos);
//    else return querycol(node*2+1,mid+1,ends,pos);
//}

void upchain(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,1,n,dfn[top[x]],dfn[x],val);
        x=f[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    update(1,1,n,dfn[x],dfn[y],val);
}
int querychain(int x,int y){
    int res=0;
    int L1=-1,L2=-1,Lc,Rc;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]){
            swap(x,y);
            swap(L1,L2);
        }
        res+=querycnt(1,1,n,dfn[top[x]],dfn[x],Lc,Rc);
//        cout<<" l "<<dfn[top[x]]<<" r "<<dfn[x]<<endl;
//        cout<<"debug "<<res<<endl;
        if(L1==Rc) res--;
        L1=Lc;x=f[top[x]];
    }
    if(dep[x]<dep[y]){
        swap(x,y);swap(L1,L2);
    }
    res+=querycnt(1 ,1,n,dfn[y],dfn[x],Lc,Rc);
    if(Rc==L1) res--;
    if(Lc==L2) res--;
    return res;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(head,-1,sizeof head);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
    }
    dfs1(1,1);
    dfs2(1,1);
    build(1,1,n);

//    for(int i=1;i<=n;i++){
//        cout<<"dfn  "<<i<<" "<<top[i]<<endl;
//    }

    for(int i=1;i<=m;i++){
        char opt;
        cin>>opt;
        if(opt=='C'){
            int x,y,z;
            cin>>x>>y>>z;
            upchain(x,y,z);
        }
        else{
            int x,y;
            cin>>x>>y;
            cout<<querychain(x,y)<<endl;
        }
    }


}

以上是关于[SDOI2011]染色 (线段树维护子段问题+树剖)的主要内容,如果未能解决你的问题,请参考以下文章

[SDOI2011]染色

SDOI2011染色

B20J_2243_[SDOI2011]染色_树链剖分+线段树

luogu P2486 [SDOI2011]染色

[SDOI2011]染色

[Luogu 2486] SDOI2011 染色