首页 > 其他分享 >P2486 [SDOI2011] 染色

P2486 [SDOI2011] 染色

时间:2023-11-11 10:45:08浏览次数:37  
标签:return int 染色 top mid SDOI2011 maxn P2486 col

题目描述

给定一棵 \(n\) 个节点的无根树,共有 \(m\) 个操作,操作分为两种:

  1. 将节点 \(a\) 到节点 \(b\) 的路径上的所有点(包括 \(a\) 和 \(b\))都染成颜色 \(c\)。
  2. 询问节点 \(a\) 到节点 \(b\) 的路径上的颜色段数量。

颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:112221

数据规模与约定

对于 \(100\%\) 的数据,\(1 \leq n, m \leq 10^5\),\(1 \leq w_i, c \leq 10^9\),\(1 \leq a, b, u, v \leq n\),\(op\) 一定为 CQ,保证给出的图是一棵树。

除原数据外,还存在一组不计分的 hack 数据。

思路:

首先仔细观察一下题目,要求一条路径上的颜色段个数,这个东西看起来就很树链剖分。因为重链剖分有一个很优秀的性质:一条重链上的 \(dfs\) 序是连续的。

所以我们不妨将一条路径拆成若干个重链和一些不太完整的重链。然后就可以进行修改和询问操作了。

有一个细节需要注意,就是在代码实现的时候需要记录一下两个端点的颜色,在线段树 \(pushup,pushdown\) 的时候需要注意交点处颜色是否相同。

然后在查询的时候,一次跳重链算出所有的链内部的段数,然后对于重链相交的地方,在遍历一遍,如果相交的地方颜色相等,答案就要减一。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define set(a,b) memset(a,b,sizeof(a))
#define ls i<<1
#define rs i<<1|1
#define pb push_back
#define pt putchar
#define All(a) a.begin(),a.end()
#define T int t;cin>>t;while(t--)
#define rand RAND
using namespace std;
char buf[1<<20],*p1,*p2;
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
template<class Typ> Typ &re(Typ &x){char ch=gc(),sgn=0; x=0;for(;ch<'0'||ch>'9';ch=gc()) sgn|=ch=='-';for(;ch>='0'&&ch<='9';ch=gc()) x=x*10+(ch^48);return sgn&&(x=-x),x;}
template<class Typ> void wt(Typ x){if(x<0) putchar('-'),x=-x;if(x>9) wt(x/10);putchar(x%10^48);}
const int inf=0x3f3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;
int seed = 19243;
unsigned rand(){return seed=(seed*48271ll)%2147483647;}
int n,m;
int a[maxn];
vector<int>G[maxn];
int fa[maxn],dep[maxn],sz[maxn],son[maxn];
void dfs(int u,int f){
    son[u]=-1;
    fa[u]=f;
    dep[u]=dep[f]+1;
    sz[u]=1;
    for(int v:G[u]){
        if(v==f)continue;
        dfs(v,u);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]]||son[u]==-1)son[u]=v;
    }
}
int idx,dfn[maxn],top[maxn],rnk[maxn];
int col[maxn];
void dfs1(int u,int tp){
    top[u]=tp;
    dfn[u]=++idx;
    rnk[idx]=u;
    col[idx]=a[u];
    if(son[u]==-1)return ;
    dfs1(son[u],tp);
    for(int v:G[u]){
        if(v==son[u] or v==fa[u])continue;
        dfs1(v,v);
    }
}
struct Seg{
    int sum[maxn<<2],tag[maxn<<2];
    void push_up(int i,int mid){
        sum[i]=sum[ls]+sum[rs];
        if(col[mid]==col[mid+1])sum[i]--;
        return ;
    }
    void build(int l,int r,int i){
        if(l==r){
            sum[i]=1;
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        push_up(i,mid);
    }
    void push_down(int i,int mid){
        if(!tag[i])return ;
        tag[ls]=tag[rs]=tag[i];
        col[mid]=col[mid+1]=tag[i];
        sum[ls]=sum[rs]=1;
        tag[i]=0;
        return ;
    }
    void update(int l,int r,int L,int R,int x,int i){
        if(L<=l&&R>=r){
            sum[i]=1;
            col[l]=col[r]=tag[i]=x;
            return ;
        }
        int mid=(l+r)>>1;
        push_down(i,mid);
        if(L<=mid)update(l,mid,L,R,x,ls);
        if(R>mid)update(mid+1,r,L,R,x,rs);
        push_up(i,mid);
    }
    int query(int l,int r,int L,int R,int i){
        if(L<=l&&R>=r){
            return sum[i];
        }
        int mid=(l+r)>>1;
        push_down(i,mid);
        int ans=0;
        if(L<=mid)ans+=query(l,mid,L,R,ls);
        if(R>mid)ans+=query(mid+1,r,L,R,rs);
        if(L<=mid&&R>mid&&col[mid]==col[mid+1])ans--;
        return ans;
    }
}tree;
void change(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        tree.update(1,n,dfn[top[x]],dfn[x],k,1);
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    tree.update(1,n,dfn[x],dfn[y],k,1);
    return ;
}
int get(int x,int y){
    int u=x,v=y,ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=tree.query(1,n,dfn[top[x]],dfn[x],1);
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    ans+=tree.query(1,n,dfn[x],dfn[y],1);
    while(top[u]!=top[v]){
        // cout<<u<<endl;
        if(dep[top[u]]<dep[top[v]])swap(u,v);
        if(col[dfn[top[u]]]==col[dfn[fa[top[u]]]])ans--;
        u=fa[top[u]];
    }
    return ans;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        G[u].pb(v);
        G[v].pb(u);
    }
    dfs(1,0);
    dfs1(1,1);
    tree.build(1,n,1);
    while(m--){
        char op;
        cin>>op;
        int a,b,c;
        if(op=='C'){
            cin>>a>>b>>c;
            change(a,b,c);
        }
        else{
            cin>>a>>b;
            cout<<get(a,b)<<endl;
        }
    }
    return 0;
}

标签:return,int,染色,top,mid,SDOI2011,maxn,P2486,col
From: https://www.cnblogs.com/Candycar/p/17825612.html

相关文章

  • 2023.08.12-美团-第五题-树上染色
    给定一棵树,每个节点都有一个权值以及最开始是白色。定义操作A:选择两个有边直接相连的节点,可以将两个节点同时染红.当且仅当他们都是白色但是这样的题目太过简单,所以我们定义一个更复杂的操作B:在满足操作A的条件下两个节点的权值的乘积也需要是x∗x的形式,现在允许执行操作若......
  • 动态规划之房屋染色
    这里有n个房子在一列直线上,现在我们需要给房屋染色,共有k种颜色。每个房屋染不同的颜色费用也不同,你希望每两个相邻的房屋颜色不同费用通过一个nxk的矩阵给出,比如cost[0][0]表示房屋0染颜色0的费用,cost[1][2]表示房屋1染颜色2的费用。样例:输入:costs=[[14,2,11],[11,14,5],[......
  • P3177 [HAOI2015] 树上染色
    P3177[HAOI2015]树上染色[P3177HAOI2015]树上染色-洛谷|计算机科学教育新生态(luogu.com.cn)目录P3177[HAOI2015]树上染色题目大意思路code题目大意有一棵\(n\)个点的树,你可以在上面把\(k\)个点染成黑色,收益为黑点两两之间的距离和加上白点两两之间的距离和求......
  • seqkit软件根据染色体名称从fasta文件中批量提取数据
     001、[root@pc1test1]#lsa.fachr.list[root@pc1test1]#cata.fa##测试fasta>chr1tttcccggg>chr2tttgggccc>chr3cccttt>chr4aaaaattt[root@pc1test1]#catchr.list##染色体列表chr2chr4[root@pc1test1]#seqkit-w8......
  • Linux awk给fasta中重复的染色体名做重复标记
     001、[root@pc1test1]#lsa.txt[root@pc1test1]#cata.txt##测试文件>jcf718000347055627>jcf718000347055638>jcf7180003470552496>jcf718000347054653>jcf718000347055862>jcf718000347055671>jcf718000347055085&......
  • 解题报告P2486 [SDOI2011] 染色
    P2486[SDOI2011]染色题目链接分两段,最后靠同一条重链合树剖加线段树,典中典。这题的线段树维护比较新颖。线段树中维护这个区间左右端点的颜色和颜色段数量。建树和查询和修改时要判断左区间的右端点和右区间的左端点是否颜色相同。如果不相同,直接将段数相加,否则减一。然......
  • gatk 实现基于染色体合并gvcf文件,并获取变异
     001、基于染色体合并gvcf文件gatkCombineGVCFs-Rreference.fna-Vgvcf.list-LchrN-OchrN.merged.g.vcf.gz其中:referen.fna是参考基因组;gvcf.list是将要合并的gvcf文件的列表文件,一行一个个体;格式如下:ERR2985607.g.vcfERR2985608.g.vcfERR2985609.g.vcfERR2......
  • 「SDOI2011」 黑白棋
    绷不住了,洛谷上的dp没一个表述清楚了,一怒之下写一篇题解。注意本题解只讲dp部分。首先转化不合法的充要条件就是:设相邻两个棋子中间间隔数量为\(b\),那么对于任意非负整数\(i\)都有\((d+1)|\sum(b\&2^i)\)。其中\(\&\)是按位与运算。所以我们要计数一个有序的并且包含......
  • P2486 [SDOI2011] 染色 题解
    P2486[SDOI2011]染色神仙树剖题。题意给你一棵树,每个点都有颜色,支持下面两种操作:路径染色。路径颜色段数量查询。树剖部分我们看到树上问题,不好处理,所以想办法给他树剖搞一搞,给他转化成序列的操作。我们树剖就是正常的树剖,然后我们考虑如何维护这个颜色序列。我......
  • RIdeogram染色体可视化
    Circos玩多了难免会视觉疲劳,今天换一个新工具可视化,回到直条的染色体形式。https://www.jianshu.com/p/07ae1fe18071https://cran.r-project.org/web/packages/RIdeogram/vignettes/RIdeogram.html#install.packages('RIdeogram')library(RIdeogram)library(plyr)library(dp......