• BZOJ2243:[SDOI2011]染色——题解


    http://www.lydsy.com/JudgeOnline/problem.php?id=2243

    Description

    给定一棵有n个节点的无根树和m个操作,操作有2类:
    1、将节点a到节点b路径上所有点都染成颜色c;
    2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
    如“112221”由3段组成:“11”、“222”和“1”。
    请你写一个程序依次完成这m个操作。

    Input

    第一行包含2个整数n和m,分别表示节点数和操作数;
    第二行包含n个正整数表示n个节点的初始颜色
    下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
    下面 行每行描述一个操作:
    “C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
    “Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

    Output

    对于每个询问操作,输出一行答案。

    Sample Input

    6 5
    2 2 1 2 1 1
    1 2
    1 3
    2 4
    2 5
    2 6
    Q 3 5
    C 2 1 1
    Q 3 5
    C 5 1 2
    Q 3 5

    Sample Output

    3
    1
    2

    HINT

    数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

    ————————————————————————————————

    (吐槽一下BZOJ,洛谷能过的代码BZOJ RE……后来优化了读入才AC……坑爹啊)

    首先是树链剖分的裸题。点这里看树链剖分原理

    然后考虑合并区间时候的问题。

    我们记录每个区间的端点颜色,区间个数,当然还有lazy标记。

    然后区间合并看相邻的端点颜色是否一致,如果一致答案就-1。

    树上需要特意查重路径的顶点和他爸颜色是否一致,如果一致答案就-1。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int N=100001;
    int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int to;
        int nxt;
    }edge[2*N];
    struct tree{
        int lc;
        int rc;
        int num;
        int lazy;
    }t[4*N];
    int head[N],cnt=0,n;
    void add(int u,int v){
        cnt++;
        edge[cnt].to=v;
        edge[cnt].nxt=head[u];
        head[u]=cnt;
        return;
    }
    int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N];
    int val[N];
    void dfs1(int u){
        size[u]=1;
        for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa[u])continue;
        fa[v]=u;dep[v]=dep[u]+1;
        dfs1(v);
        size[u]+=size[v];
        if(!son[u]||size[v]>size[son[u]])son[u]=v;
        }
        return;
    }
    int tot;
    void dfs2(int u,int anc){
        tot++;
        pos[u]=tot;
        idx[tot]=u;
        top[u]=anc;
        if(!son[u])return;
        dfs2(son[u],anc);
        for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
        }
        return;
    }
    void init(){
        dfs1(1);
        top[1]=idx[1]=pos[1]=1;
        tot=0;
        dfs2(1,1);
        return;
    }
    void pushdown(int a){
        if(t[a].lazy!=-1){
        t[a*2].lazy=t[a*2+1].lazy=t[a].lazy;
        t[a*2].lc=t[a*2].rc=t[a].lazy;
        t[a*2+1].lc=t[a*2+1].rc=t[a].lazy;
        t[a*2].num=t[a*2+1].num=1;
        t[a].lazy=-1;
        }
        return;
    }
    void build(int a,int l,int r){
        t[a].lazy=-1;
        if(l==r){
        t[a].lc=val[idx[l]];
        t[a].rc=val[idx[l]];
        t[a].num=1;
        return;
        }
        int mid=(l+r)>>1;
        build(a*2,l,mid);
        build(a*2+1,mid+1,r);
        t[a].lc=t[a*2].lc;t[a].rc=t[a*2+1].rc;
        t[a].num=t[a*2].num+t[a*2+1].num;
        if(t[a*2].rc==t[a*2+1].lc)t[a].num--;
        return;
    }
    int query(int a,int l,int r,int l1,int r1){
        if(r1<l||l1>r)return 0;
        if(l1<=l&&r<=r1){
        return t[a].num;
        }
        int mid=(l+r)>>1;
        pushdown(a);
        int k1=query(a*2,l,mid,l1,r1);
        int k2=query(a*2+1,mid+1,r,l1,r1);
        if(k1&&k2){
        if(t[a*2].rc==t[a*2+1].lc)k1--;
        }
        return k1+k2;
    }
    int check(int a,int l,int r,int k){
        if(l==r)return t[a].lc;
        int mid=(l+r)>>1;
        pushdown(a);
        if(l<=k&&k<=mid)return check(a*2,l,mid,k);
        else if(mid<k&&k<=r)return check(a*2+1,mid+1,r,k);
    }
    int pathquery(int u,int v){
        int res=0;
        while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
        int ans=query(1,1,n,pos[top[u]],pos[u]);
        if(check(1,1,n,pos[top[u]])==check(1,1,n,pos[fa[top[u]]]))ans--;
        res+=ans;
        u=fa[top[u]];
        }
        if(dep[u]>dep[v]){int t=u;u=v;v=t;}
        return res+query(1,1,n,pos[u],pos[v]);
    }
    void modify(int a,int l,int r,int l1,int r1,int v){
        if(r1<l||r<l1)return;
        if(l1<=l&&r<=r1){
        t[a].lazy=v;
        t[a].lc=v;t[a].rc=v;
        t[a].num=1;
        return;
        }
        int mid=(l+r)>>1;
        pushdown(a);
        modify(a*2,l,mid,l1,r1,v);
        modify(a*2+1,mid+1,r,l1,r1,v);
        t[a].lc=t[a*2].lc;t[a].rc=t[a*2+1].rc;
        t[a].num=t[a*2].num+t[a*2+1].num;
        if(t[a*2].rc==t[a*2+1].lc)t[a].num--;
        return;
    }
    void pathmodify(int u,int v,int c){
        while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
        modify(1,1,n,pos[top[u]],pos[u],c);
        u=fa[top[u]];
        }
        if(dep[u]>dep[v]){int t=u;u=v;v=t;}
        modify(1,1,n,pos[u],pos[v],c);
        return;
    }
    int main(){
        n=read();int q=read();
        for(int i=1;i<=n;i++)val[i]=read();
        for(int i=2;i<=n;i++){
        int u=read();
        int v=read();
        add(u,v);
        add(v,u);
        }
        init();
        build(1,1,n);
        while(q--){
        char op=0;
        while(op!='C'&&op!='Q')op=getchar();
        if(op=='C'){
            int a=read();
            int b=read();
            int c=read();
            pathmodify(a,b,c);
        }else{
            int a=read();
            int b=read();
            printf("%d
    ",pathquery(a,b));
        }
        }
        return 0;
    }
  • 相关阅读:
    JS使用readAsDataURL读取图像文件
    python20个骚操作
    HTML标签的for属性
    进程、线程、协程理解
    mysql 深度解析auto-increment自增列"Duliplicate key"问题
    2020年MySQL数据库面试题总结(50道题含答案解析)
    如何用Redis统计独立用户访问量
    Redis中的布隆过滤器及其应用
    redis系列教程以及面试题
    大厂面试爱问的「调度算法」,20 张图一举拿下
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/7891126.html
Copyright © 2020-2023  润新知