zoukankan      html  css  js  c++  java
  • 洛谷P2486 [SDOI2011]染色

    原题传送门

    题目描述

    输入输出格式

    输入格式:

    输出格式:

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

    输入输出样例

    输入样例#1: 
    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
    
    输出样例#1: 
    3
    1
    2
    

    说明

    题解

    看到一棵树,看到区间操作,首先想到的就是树链剖分+线段树

    这道题是非常规区间操作的典型题(需要合并区间)

    这道题的线段树部分不是求和或区间最值,而是某种特定的区间操作(区间赋值+区间查询连续相同值段数),故需要更改push_up的部分

    inline void push_up(int x){
        L[x]=L[x<<1];
        R[x]=R[x<<1|1];
        cnt[x]=cnt[x<<1]+cnt[x<<1|1]-(R[x<<1]==L[x<<1|1]);
    }

    我们记录每一段区间左右端点的颜色,合并时如果左区间的右端点的颜色和右区间的左端点的颜色相同,需要将计数器减1

    至于线段树的其他部分,也要相应地做一些简单改变,具体见代码

    树链剖分的路径查询环节也要改一下,需要支持区间合并,即当两段链交界处颜色相同时需要将计数器减1

    int ret=0,l=-1,r=-1;
    while(top[ii]!=top[jj]){
        if(de[top[ii]]<de[top[jj]]){
            swap(ii,jj);
            swap(l,r);
        }
        ret+=query(1,1,N,dfn[top[ii]],dfn[ii]);
        if(l==Rc){
            ret--;
        }
        l=Lc;
        ii=f[top[ii]];
    }
    if(de[ii]<de[jj]){
        swap(ii,jj);
        swap(l,r);
    }
    ret+=query(1,1,N,dfn[jj],dfn[ii]);
    if(l==Rc){
        ret--;
    }
    if(r==Lc){
        ret--;
    }
    printf("%d
    ",ret);

    注意这段代码中的Lc和Rc是模板中没有的。Lc是全局变量,表示当前查询区间的左端点的颜色,Rc也是全局变量,表示当前查询区间右端点的颜色

    Lc和Rc可以在query函数中顺便求得

    int query(int x,int l,int r,int ql,int qr){
        if(l>r||l>qr||r<ql){
            return 0;
        }
        if(l==ql){
            Lc=L[x];
        }
        if(r==qr){
            Rc=R[x];
        }
        if(ql<=l&&r<=qr){
            return cnt[x];
        }
        int mid=(l+r)>>1,ret=0;
        push_down(x,l,r);
        ret=query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr);
        if(mid>=ql&&mid+1<=qr&&R[x<<1]==L[x<<1|1]){
            ret--;
        }
        return ret;
    }

    至此,所有的技术难题都解决了,题目也就迎刃而解了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7,MAXN=1e5+1,MAXM=2e5+1;
    int N,M;
    int head[MAXN],to[MAXM],nxt[MAXM],tp=1;
    inline void add(int x,int y){
        nxt[++tp]=head[x];
        head[x]=tp;
        to[tp]=y;
        nxt[++tp]=head[y];
        head[y]=tp;
        to[tp]=x;
    }
    int f[MAXN],de[MAXN],son[MAXN],siz[MAXN];
    void dfs1(int x,int fa,int d){
        f[x]=fa;
        de[x]=d;
        siz[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            if(to[i]!=fa){
                dfs1(to[i],x,d+1);
                if(siz[to[i]]>siz[son[x]]){
                    son[x]=to[i];
                }
                siz[x]+=siz[to[i]];
            }
        }
    }
    int dfn[MAXN],top[MAXN],timeclock;
    int tmp[MAXN],val[MAXN],cnt[MAXN*3],tag[MAXN*3],L[MAXN*3],R[MAXN*3];
    void dfs2(int x,int t){
        top[x]=t;
        dfn[x]=++timeclock;
        val[dfn[x]]=tmp[x];
        if(son[x]){
            dfs2(son[x],t);
        }
        for(int i=head[x];i;i=nxt[i]){
            if(to[i]!=f[x]&&to[i]!=son[x]){
                dfs2(to[i],to[i]);
            }
        }
    }
    inline void push_up(int x){
        L[x]=L[x<<1];
        R[x]=R[x<<1|1];
        cnt[x]=cnt[x<<1]+cnt[x<<1|1]-(R[x<<1]==L[x<<1|1]);
    }
    inline void push_down(int x,int l,int r){
        int &ii=tag[x];
        if(ii&&l!=r){
            tag[x<<1]=tag[x<<1|1]=ii;
            cnt[x<<1]=cnt[x<<1|1]=1;
            L[x<<1]=R[x<<1]=L[x<<1|1]=R[x<<1|1]=ii;
            ii=0;
        }
    }
    void init(int x,int l,int r){
        if(l==r){
            L[x]=R[x]=val[l];
            cnt[x]=1;
        }else{
            int mid=(l+r)>>1;
            init(x<<1,l,mid);
            init(x<<1|1,mid+1,r);
            push_up(x);
        }
    }
    void update(int x,int l,int r,int ql,int qr,int c){
        if(l>r||l>qr||r<ql){
            return;
        }
        if(ql<=l&&r<=qr){
            L[x]=R[x]=tag[x]=c;
            cnt[x]=1;
            return;
        }
        push_down(x,l,r);
        int mid=(l+r)>>1;
        update(x<<1,l,mid,ql,qr,c);
        update(x<<1|1,mid+1,r,ql,qr,c);
        push_up(x);
    }
    int Rc,Lc;
    int query(int x,int l,int r,int ql,int qr){
        if(l>r||l>qr||r<ql){
            return 0;
        }
        if(l==ql){
            Lc=L[x];
        }
        if(r==qr){
            Rc=R[x];
        }
        if(ql<=l&&r<=qr){
            return cnt[x];
        }
        int mid=(l+r)>>1,ret=0;
        push_down(x,l,r);
        ret=query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr);
        if(mid>=ql&&mid+1<=qr&&R[x<<1]==L[x<<1|1]){
            ret--;
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++){
            scanf("%d",tmp+i);
        }
        for(int i=1;i<N;i++){
            int ii,jj;
            scanf("%d%d",&ii,&jj);
            add(ii,jj);
        }
        dfs1(1,1,1);
        dfs2(1,1);
        init(1,1,N);
        for(int i=1;i<=M;i++){
            char op;
            int ii,jj,kk;
            scanf(" %c",&op);
            if(op=='C'){
                scanf("%d%d%d",&ii,&jj,&kk);
                while(top[ii]!=top[jj]){
                    if(de[top[ii]]<de[top[jj]]){
                        swap(ii,jj);
                    }
                    update(1,1,N,dfn[top[ii]],dfn[ii],kk);
                    ii=f[top[ii]];
                }
                if(de[ii]<de[jj]){
                    swap(ii,jj);
                }
                update(1,1,N,dfn[jj],dfn[ii],kk);
            }else{
                scanf("%d%d",&ii,&jj);
                int ret=0,l=-1,r=-1;
                while(top[ii]!=top[jj]){
                    if(de[top[ii]]<de[top[jj]]){
                        swap(ii,jj);
                        swap(l,r);
                    }
                    ret+=query(1,1,N,dfn[top[ii]],dfn[ii]);
                    if(l==Rc){
                        ret--;
                    }
                    l=Lc;
                    ii=f[top[ii]];
                }
                if(de[ii]<de[jj]){
                    swap(ii,jj);
                    swap(l,r);
                }
                ret+=query(1,1,N,dfn[jj],dfn[ii]);
                if(l==Rc){
                    ret--;
                }
                if(r==Lc){
                    ret--;
                }
                printf("%d
    ",ret);
            }
        }
        return 0;
    }
  • 相关阅读:
    Atcoder Tenka1 Programmer Contest 2019 D Three Colors
    Codeforces 1146E Hot is Cold
    ZOJ 3820 Building Fire Stations
    ZOJ 3822 Domination
    ZOJ 3949 Edge to the Root
    Codeforces 1144G Two Merged Sequences
    PTA 团体程序设计天梯赛 L3-020 至多删三个字符
    BZOJ 5102: [POI2018]Prawnicy
    BZOJ 1045: [HAOI2008] 糖果传递
    2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/10568785.html
Copyright © 2011-2022 走看看