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

    Description:

    Hint:

    (n le 10^5)

    Solution:

    掌握了线段树区间合并的套路,这题就很简单了,树剖之后用线段树维护左右颜色,和区间颜色段数,查询跳链时分类讨论一下中间的颜色是否相同,修改直接修改就行了,代码稍有细节

    #include<bits/stdc++.h>
    #define ls p<<1
    #define rs p<<1|1
    using namespace std;
    const int mxn=1e6+5;
    int n,m,tot,cnt;
    int a[mxn],v[mxn<<2],f[mxn],hd[mxn],lc[mxn],rc[mxn],sz[mxn],rk[mxn];
    int dfn[mxn],top[mxn],son[mxn],coll[2],colr[2],dep[mxn],tag[mxn<<2];
    
    struct ed {
        int to,nxt;
    }t[mxn<<1];
    
    inline void add(int u,int v) {
        t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
    };
    
    void push_up(int p)
    {
        lc[p]=lc[ls]; rc[p]=rc[rs]; v[p]=v[ls]+v[rs];
        if(rc[ls]==lc[rs]) --v[p];
    }
    
    void push_down(int p)
    {
        if(tag[p]) {
            tag[ls]=tag[rs]=tag[p];
            v[ls]=v[rs]=1;
            lc[ls]=lc[rs]=rc[ls]=rc[rs]=tag[p];
            tag[p]=0;
        }
    }
    
    void build(int l,int r,int p)
    {
        if(l==r) {
            v[p]=1; lc[p]=rc[p]=a[rk[l]];
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        push_up(p);
    }
    
    void dfs1(int u,int fa)
    {
        f[u]=fa; sz[u]=1; dep[u]=dep[fa]+1;
        for(int i=hd[u];i;i=t[i].nxt) {
            int v=t[i].to;
            if(v==fa) continue ;
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
    
    void dfs2(int u,int tp)
    {
        top[u]=tp; dfn[u]=++tot; rk[tot]=u; 
        if(son[u]) dfs2(son[u],tp);
        for(int i=hd[u];i;i=t[i].nxt) {
            int v=t[i].to;
            if(v==f[u]||v==son[u]) continue ;
            dfs2(v,v);
        }
    }
    
    void getcol(int l,int r,int ql,int qr,int id,int p)
    {
        if(ql<=l&&r<=qr) {
            if(ql==l) coll[id]=lc[p];
            if(qr==r) colr[id]=rc[p];
            return ;
        }
        int mid=(l+r)>>1; push_down(p);
        if(qr>mid) getcol(mid+1,r,ql,qr,id,rs);
        if(ql<=mid) getcol(l,mid,ql,qr,id,ls);
        push_up(p);
    }
    
    int query(int l,int r,int ql,int qr,int id,int p)
    {	
        if(ql<=l&&r<=qr) return v[p]; 
        int mid=(l+r)>>1; int lt=0,rt=0,res=0; push_down(p);
        if(ql<=mid) res+=query(l,mid,ql,qr,id,ls),lt=1;
        if(qr>mid) res+=query(mid+1,r,ql,qr,id,rs),rt=1;
        if(lt&&rt) res-=(rc[ls]==lc[rs]); return res;
    }
    
    void update(int l,int r,int ql,int qr,int val,int p)
    {
        if(ql<=l&&r<=qr) {
            tag[p]=val;
            v[p]=1; lc[p]=rc[p]=val;
            return ;
        }
        int mid=(l+r)>>1; push_down(p);
        if(ql<=mid) update(l,mid,ql,qr,val,ls);
        if(qr>mid) update(mid+1,r,ql,qr,val,rs);
        push_up(p);
    }
    
    void solve(int x,int y)
    {
        int ans=0,las1=-1,las2=-1; coll[0]=coll[1]=colr[0]=colr[1]=-1; //注意颜色可能为0,因为这里调了好久
        int fx=top[x],fy=top[y];
        while(fx!=fy) {
            if(dep[fx]>=dep[fy]) {
                ans+=query(1,n,dfn[fx],dfn[x],0,1);
                getcol(1,n,dfn[fx],dfn[x],0,1);
                if(las1==colr[0]) --ans;
                x=f[fx],fx=top[x]; las1=coll[0];
            }
            else { 
                ans+=query(1,n,dfn[fy],dfn[y],1,1);
                getcol(1,n,dfn[fy],dfn[y],1,1);
                if(las2==colr[1]) --ans;
                y=f[fy],fy=top[y]; las2=coll[1];
            } 
        } 
     
        if(dfn[x]>dfn[y]) swap(x,y),swap(las1,las2);
        getcol(1,n,dfn[x],dfn[y],1,1);
        printf("%d
    ",ans+query(1,n,dfn[x],dfn[y],1,1)-(colr[1]==las2)-(coll[1]==las1));
    }
    
    void modify(int x,int y,int z)
    {
        int fx=top[x],fy=top[y];
        while(fx!=fy) {
            if(dep[fx]>=dep[fy]) {
                update(1,n,dfn[fx],dfn[x],z,1);
                x=f[fx],fx=top[x];
            }
            else {
                update(1,n,dfn[fy],dfn[y],z,1);
                y=f[fy],fy=top[y];
            }
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        update(1,n,dfn[x],dfn[y],z,1);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m); char opt[5]; int u,v,w;
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        for(int i=1;i<n;++i) {
            scanf("%d%d",&u,&v);
            add(u,v); add(v,u);
        }
        dfs1(1,0); dfs2(1,1); build(1,n,1);
        for(int i=1;i<=m;++i) {
            scanf("%s",opt);
            if(opt[0]=='Q') {
                scanf("%d%d",&u,&v);
                solve(u,v);
            }
            else if (opt[0]=='C') {
                scanf("%d%d%d",&u,&v,&w);
                modify(u,v,w);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    OpenCV-Python 模板匹配 | 三十一
    OpenCV-Python 傅里叶变换 | 三十
    OpenCV-Python 直方图-3:二维直方图 | 二十八
    OpenCV-Python 直方图-4:直方图反投影 | 二十九
    角谷猜想
    C# Notepad++ 环境配置
    C++ Notepad++ 环境配置
    字符串内无重复字符的最长子串长度
    计算给定字符串的无重复字符的最长子串长度
    黑色星期五
  • 原文地址:https://www.cnblogs.com/list1/p/10446058.html
Copyright © 2011-2022 走看看