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

    Link:

    BZOJ 2243 传送门

    Solution:

    基础树剖,但要注意的就是链合并时的边界问题

    每次查询时发现当前区间为目标区间的边界时直接记录边界的值即可

    注意最后一次两个边界都要考虑!

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    #define pb push_back
    #define mid ((l+r)>>1)
    #define lc k<<1,l,mid
    #define rc k<<1|1,mid+1,r
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10;
    struct edge{int nxt,to;}e[MAXN<<2];
    int tag[MAXN<<2],seg[MAXN<<2],lb[MAXN<<2],rb[MAXN<<2];
    int LC,RC;
    int n,m,l,r,k,col[MAXN],dat[MAXN],head[MAXN],tot,cnt;
    int sz[MAXN],top[MAXN],f[MAXN][20],dep[MAXN],pos[MAXN];
    
    void add_edge(int x,int y)
    {
        e[++tot]=(edge){head[x],y};head[x]=tot;
        e[++tot]=(edge){head[y],x};head[y]=tot;
    }
    void dfs1(int x)
    {
        sz[x]=1;
        for(int i=1;(1<<i)<=dep[x];i++)
            f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==f[x][0]) continue;
            f[e[i].to][0]=x;dep[e[i].to]=dep[x]+1;
            dfs1(e[i].to);sz[x]+=sz[e[i].to];
        }
    }
    void dfs2(int x,int up)
    {
        int bs=0;
        pos[x]=++cnt;top[x]=up;
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=f[x][0]&&sz[e[i].to]>sz[bs])
                bs=e[i].to;
        if(!bs) return;
        dfs2(bs,up);
        
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=f[x][0]&&e[i].to!=bs)
                dfs2(e[i].to,e[i].to);
    }
    int LCA(int u,int v)
    {
        while(top[u]!=top[v])
        {
            if(dep[top[u]]<dep[top[v]])
                swap(u,v);
            u=f[top[u]][0];
        }
        if(dep[u]>dep[v]) swap(u,v);
        return u;
    }
    
    void pushup(int k)
    {
        lb[k]=lb[k<<1];rb[k]=rb[k<<1|1];
        seg[k]=seg[k<<1]+seg[k<<1|1]-(rb[k<<1]==lb[k<<1|1]);
    }
    void pushdown(int k)
    {
        if(!tag[k]) return;
        seg[k<<1]=seg[k<<1|1]=1;
        tag[k<<1]=lb[k<<1]=rb[k<<1]=tag[k];
        tag[k<<1|1]=lb[k<<1|1]=rb[k<<1|1]=tag[k];
        tag[k]=0;
    }
    void build(int k,int l,int r)
    {
        if(l==r)
        {lb[k]=rb[k]=col[l];seg[k]=1;return;}
        build(lc);build(rc);
        pushup(k);
    }
    void Update(int a,int b,int x,int k,int l,int r)
    {
        if(a<=l&&r<=b)
        {tag[k]=lb[k]=rb[k]=x;seg[k]=1;return;}
        pushdown(k);
        if(a<=mid) Update(a,b,x,lc);
        if(b>mid) Update(a,b,x,rc);
        pushup(k);
    }
    int Query(int a,int b,int k,int l,int r)
    {//直接记录当次的最左/右处的颜色 
        if(l==a) LC=lb[k];
        if(r==b) RC=rb[k];
        if(a<=l&&r<=b) return seg[k];
        
        pushdown(k);
        int ret=0,cnt=0;
        if(a<=mid) ret+=Query(a,b,lc),cnt++;
        if(b>mid) ret+=Query(a,b,rc),cnt++;
        if(cnt==2) ret-=rb[k<<1]==lb[k<<1|1];
        return ret;
    }
    
    void solve(int u,int v,int k)
    {
        while(top[u]!=top[v])
        {
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            Update(pos[top[u]],pos[u],k,1,1,n);
            u=f[top[u]][0];
        }
        if(pos[u]>pos[v]) swap(u,v);
        Update(pos[u],pos[v],k,1,1,n);
    }
    int query(int u,int v)
    {
        int ret=0,lstu=0,lstv=0;
        while(top[u]!=top[v])
        {
            if(dep[top[u]]<dep[top[v]]) 
                swap(u,v),swap(lstu,lstv);
            ret+=Query(pos[top[u]],pos[u],1,1,n);
            ret-=RC==lstu;
            u=f[top[u]][0];lstu=LC;
        }
        
        if(pos[u]>pos[v]) 
            swap(u,v),swap(lstu,lstv);
        ret+=Query(pos[u],pos[v],1,1,n);
        //注意最后一次要处理两个边界 
        ret-=RC==lstv;ret-=LC==lstu;
        return ret;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
        for(int i=1;i<n;i++)
            scanf("%d%d",&l,&r),add_edge(l,r);
        dfs1(1);dfs2(1,1);
        for(int i=1;i<=n;i++) col[pos[i]]=dat[i];
        build(1,1,n);
        
        while(m--)
        {
            char s[10];
            scanf("%s%d%d",s,&l,&r);
            if(s[0]=='C')
                scanf("%d",&k),solve(l,r,k);
            else printf("%d
    ",query(l,r));
        }
        return 0;
    }
  • 相关阅读:
    java+opencv实现图像灰度化
    java实现高斯平滑
    hdu 3415 单调队列
    POJ 3368 Frequent values 线段树区间合并
    UVA 11795 Mega Man's Mission 状态DP
    UVA 11552 Fewest Flops DP
    UVA 10534 Wavio Sequence DP LIS
    UVA 1424 uvalive 4256 Salesmen 简单DP
    UVA 1099 uvalive 4794 Sharing Chocolate 状态DP
    UVA 1169uvalive 3983 Robotruck 单调队列优化DP
  • 原文地址:https://www.cnblogs.com/newera/p/9705724.html
Copyright © 2011-2022 走看看