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

    传送门

    题目大意:一棵树,节点一开始有颜色并都相同。有两种操作a--b路径上所有点染成c,

    求a-b路径上有多少个颜色连续的序列。

    题解:树链剖分

    线段树需要记录区间个数sum,区间左右端点的颜色lc,rc,还有懒标记。

    其他需要注意的就是端点了。

    如:用线段树统计区间[l,r]有多少连续的颜色序列时,pushup操作

    tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum-(tr[rt<<1].rc==tr[rt<<1|1].lc)

    询问区间sum时,最好用三段式查询,判断合并区间的左儿子的右端点

    颜色和右儿子的左端点颜色是否相等,若相等所求sum--。

    轻重链跳跃时(query()函数),查询top[y]和top[dad[y]]的颜色是否相等,相等个数--。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100009
    using namespace std;
    
    int n,m,cnt,sumedge;
    int head[maxn],dad[maxn],size[maxn],deep[maxn],top[maxn];
    int c[maxn],re[maxn],tpos[maxn];
    char s[10];
    
    struct Tree{
        int l,r,sum,lc,rc,s;
    }tr[maxn<<2];
    
    struct Edge{
        int x,y,nxt;
        Edge(int x=0,int y=0,int nxt=0):
            x(x),y(y),nxt(nxt){}
    }edge[maxn<<1];
    
    void add(int x,int y){
        edge[++sumedge]=Edge(x,y,head[x]);
        head[x]=sumedge;
    }
    
    void dfs(int x){
        size[x]=1;deep[x]=deep[dad[x]]+1;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v==dad[x])continue;
            dad[v]=x;dfs(v);
            size[x]+=size[v];
        }
    }
    
    void dfs_(int x){
        int s=0;tpos[x]=++cnt;re[cnt]=x;
        if(!top[x])top[x]=x;
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=dad[x]&&size[v]>size[s])s=v;
        }
        if(s){
            top[s]=top[x];
            dfs_(s);
        }
        for(int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(v!=dad[x]&&v!=s)dfs_(v);
        }
    }
    
    void pushup(int rt){
        tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum-(tr[rt<<1].rc==tr[rt<<1|1].lc);
        tr[rt].lc=tr[rt<<1].lc;tr[rt].rc=tr[rt<<1|1].rc;
        return;
    }
    
    void pushdown(int rt){
        if(!tr[rt].s)return;
        tr[rt<<1].sum=tr[rt<<1|1].sum=1;
        tr[rt<<1].rc=tr[rt<<1].lc=tr[rt<<1|1].lc=tr[rt<<1|1].rc=tr[rt].s;
        tr[rt<<1].s=tr[rt<<1|1].s=tr[rt].s;
        tr[rt].s=0;return;
    }
    
    void build(int rt,int l,int r){
        tr[rt].l=l;tr[rt].r=r;
        if(l==r){
            tr[rt].sum=1;tr[rt].lc=tr[rt].rc=c[re[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
        pushup(rt);
    }
    
    void change(int rt,int l,int r,int ql,int qr,int p){
        if(l>=ql&&r<=qr){
            tr[rt].sum=1;tr[rt].lc=tr[rt].rc=p;tr[rt].s=p;
            return;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(ql<=mid)change(rt<<1,l,mid,ql,qr,p);
        if(qr>mid)change(rt<<1|1,mid+1,r,ql,qr,p);
        pushup(rt);
    }
    
    int query_sum(int rt,int l,int r,int ql,int qr){
        if(l>=ql&&r<=qr){
            return tr[rt].sum;
        }
        pushdown(rt);
        int mid=(l+r)>>1;
        if(qr<=mid)return query_sum(rt<<1,l,mid,ql,qr);
        if(ql>mid)return query_sum(rt<<1|1,mid+1,r,ql,qr);
        return query_sum(rt<<1,l,mid,ql,qr)+query_sum(rt<<1|1,mid+1,r,ql,qr)-(tr[rt<<1].rc==tr[rt<<1|1].lc);//**
    }
    
    int getcolr(int rt,int l,int r,int p){
        if(l==r)return tr[rt].lc;
        pushdown(rt);
        int mid=(l+r)>>1;
        if(p<=mid)return getcolr(rt<<1,l,mid,p);
        if(p>mid)return getcolr(rt<<1|1,mid+1,r,p);
    }
    
    int query(int x,int y){
        int ret=0;
        for(;top[x]!=top[y];){
            if(deep[top[x]]>deep[top[y]])swap(x,y);
            ret+=query_sum(1,1,n,tpos[top[y]],tpos[y]);
            if(getcolr(1,1,n,tpos[top[y]])==getcolr(1,1,n,tpos[dad[top[y]]]))ret--;
            y=dad[top[y]];
        }
        if(deep[x]>deep[y])swap(x,y);
        ret+=query_sum(1,1,n,tpos[x],tpos[y]);
        return ret;
    }
    
    void change_(int x,int y,int c){
        for(;top[x]!=top[y];){
            if(deep[top[x]]>deep[top[y]])swap(x,y);
            change(1,1,n,tpos[top[y]],tpos[y],c);
            y=dad[top[y]];
        }
        if(deep[x]>deep[y])swap(x,y);
        change(1,1,n,tpos[x],tpos[y],c);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&c[i]);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs(1);dfs_(1);build(1,1,n);
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%s",s);
            if(s[0]=='Q'){
                scanf("%d%d",&x,&y);
                printf("%d
    ",query(x,y));
            }else  {
                scanf("%d%d%d",&x,&y,&z);
                change_(x,y,z);
            }
        }
        return 0;
    }
    AC

    总结:x到top[x]在线段树上是连续的。

  • 相关阅读:
    jquery处理鼠标左中右键事件
    bootstrap弹出框
    移动端去掉a标签点击时出现的背景
    sessionStorage
    页面滑动到最下面,执行代码
    判断页面时向上滚动还是向下滚动
    sql 时间查询 /sql中判断更新或者插入/查询一年所有双休日
    求取最大值
    Repeater 获取数据值
    加载完毕后执行计算
  • 原文地址:https://www.cnblogs.com/zzyh/p/7701345.html
Copyright © 2011-2022 走看看