P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段

https://www.luogu.org/problemnew/show/P2486

值的一看https://www.cnblogs.com/Tony-Double-Sky/p/9283262.html

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100010;
vector<int>G[maxn];
int n , q ,cnt;
int siz[maxn] , wson[maxn],dep[maxn],fa[maxn],top[maxn],pos[maxn],ori[maxn];
void dfs1(int id , int F)
{
    siz[id]=1;
    for(int i=0 ; i<G[id].size() ; i++)
    {
        int v=G[id][i];
        if(v==F) continue;
        dep[v] = dep[id] + 1;
        fa[v] = id;
        dfs1(v,id);
        siz[id] += siz[v];
        if(siz[v] > siz[wson[id]]) wson[id] = v;
    }
}
void dfs2(int id , int TP)
{
    top[id] = TP;
    pos[id] = ++cnt;
    ori[cnt]=id;
    if(!wson[id]) return ;
    dfs2(wson[id],TP);
    for(int i=0 ; i<G[id].size() ; i++)
    {
        int v=G[id][i];
        if(v==fa[id] || v==wson[id]) continue;
        dfs2(v,v);
    }
}

int lc[maxn<<2] , rc[maxn<<2],col[maxn];
#define lson (id<<1)
#define rson (id<<1) | 1
struct no
{
    int l,r;
    int sum,c;///区间颜色总数 , 叶子颜色
    int lazy;///儿子的颜色

}tree[maxn<<2];
void build(int id , int l , int r)
{
    tree[id].l=l;
    tree[id].r=r;
    if(l==r)
    {
        tree[id].c=col[ori[l]];//赋值:叶子颜色
        lc[id]=rc[id]=col[ori[l]];//赋值:区间左颜色和区间右颜色
        tree[id].sum=1;//颜色数为1
        return ;
    }
    int mid = (l+r)>>1;
    build(lson , l , mid);
    build(rson , mid+1 , r);
    tree[id].sum = tree[lson].sum + tree[rson].sum;
    if(rc[lson] == lc[rson]) tree[id].sum-=1;
    lc[id] = lc[lson];
    rc[id] = rc[rson];
}
void pushdown(int id)
{
    if(tree[id].lazy!=0 && tree[id].l != tree[id].r)
    {
        int c=tree[id].lazy;
        tree[lson].lazy = tree[rson].lazy=c;
        tree[lson].c = tree[rson].c = c;
        lc[lson]=lc[rson]=rc[lson]=rc[rson]=c;
        tree[lson].sum = tree[rson].sum=1;
        tree[id].lazy=0;
    }

}
void update(int id ,int c , int l , int r)
{
    pushdown(id);
    if(tree[id].l == l && tree[id].r==r)
    {
        tree[id].c=c;
        tree[id].lazy=c;
        tree[id].sum=1;
        lc[id]=rc[id]=c;
        return ;
    }
    int mid=tree[id].l + tree[id].r >> 1;
    if(mid < l)
        update(rson,c,l,r);
    else if(mid>=r)
        update(lson,c,l,r);
    else
    {
        update(lson,c,l,mid);
        update(rson,c,mid+1,r);
    }
    tree[id].sum=tree[lson].sum+tree[rson].sum;
    if(rc[lson]==lc[rson]) tree[id].sum-=1;
    lc[id]=lc[lson];
    rc[id]=rc[rson];
}
int query(int id , int l , int r)
{
    pushdown(id);
    if(tree[id].l == l && tree[id].r==r)
    {
        return tree[id].sum;
    }
    int mid=(tree[id].l + tree[id].r) >>1;
    if(mid < l)
        return query(rson,l,r);
    else if(mid >=r)
        return query(lson,l,r);
    else
    {
        int ret = query(lson,l,mid) + query(rson,mid+1,r);
        if(rc[lson]==lc[rson]) ret-=1;
        return ret;
    }
}
int Qc(int id , int l ,int r)
{
    pushdown(id);
    if(tree[id].l==l && tree[id].r==r)
    {
        return tree[id].c;
    }
    int mid=tree[id].l + tree[id].r >>1;
    if(mid < l) return Qc(rson,l,r);
    else return Qc(lson,l,r);
}
void uprange(int x , int y , int c)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        update(1,c,pos[top[x]],pos[x]);
        x=fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    update(1,c,pos[x],pos[y]);
}
int Qsum(int x , int y)
{
    int ans=0,Cson,Cfa;
    while(top[x] != top[y])
    {

        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        ans+=query(1,pos[top[x]],pos[x]);
        Cson=Qc(1,pos[top[x]],pos[top[x]]);
        Cfa=Qc(1,pos[fa[top[x]]] , pos[fa[top[x]]]);
        if(Cson==Cfa) ans-=1;
        x=fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    ans+=query(1,pos[x] , pos[y]);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1 ; i<=n ; i++) scanf("%d",&col[i]);
    int u,v;
    for(int i=1 ; i<n ; i++)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(1,-1);
    dfs2(1,1);
    build(1,1,n);
    char ask;
    int c;
    while(q--)
    {
        cin>>ask;
        scanf("%d%d",&u,&v);
        if(ask==‘Q‘)
        {

            printf("%d\n",Qsum(u,v));
        }
        else
        {
            scanf("%d",&c);
            uprange(u,v,c);
        }
    }
}

原文地址:https://www.cnblogs.com/shuaihui520/p/10747707.html

时间: 2024-08-29 19:25:15

P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段的相关文章

luogu题解P2486[SDOI2011]染色--树链剖分+trick

题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在序列上维护信息:从最简单的想起,如果两个相邻的元素合并,显然是这两个元素所含颜色段个数(其实就是1)加起来,如果两个元素颜色相同就减1;那么两个分别含有两个元素的相邻区间合并,还是把这两个区间所含颜色段个数加起来,如果左区间最右边的颜色等于右区间最左边的颜色就减去1. 如此我们已经得到线段树维护信息

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

P2486 [SDOI2011]染色

P2486 [SDOI2011]染色 链接:https://www.luogu.org/problemnew/show/P2486 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#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 说明 题解:树连剖分+细节,用二进制记录某段染色情况,并记录最边上的颜色,不

BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n个节点的初始颜色 下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.

洛谷 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 说明 题目大意:给一棵树,要求支持链覆盖+查询链上颜色段数 先考虑链上怎么做吧,颜色段数这个东西支持区间加,一个区间可以用三个属性表示:左端点的颜色,右端点的颜色,区间颜色段数 两段合并以后的颜色段数是:左段颜色段数+右

2243: [SDOI2011]染色(树链剖分+线段树)

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 8400  Solved: 3150[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

[bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n个节点的初始颜色 下面 行每行包含两个整数x和y,表示x和y之间有一条无向边. 下面 行每行描述一个操作: “C a

【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n

luogu P2486 [SDOI2011]染色

树剖做法: 就是两个dfs+一个线段树 难度的取决基本==线段树的维护难度 所以对有点线段树基础的,树剖也不难做吧 这里操作有二 一:两点间路径染色 线段树的区间赋值操作 二:查询路径段的个数 考虑线段树如何做 我们发现两端区间的合并取决于他们相连接的那两个颜色 比如这张图 他两边区间合并的时候,完全就是左区间答案+右区间答案也就是2+2 但是这样 他们合并的答案就是2+2-1了也就是中间连接的两个颜色相同时要减1 明白了这个pushup也就不难写了 这里在说一下查询操作 由于是分开查询的,所以

bzoj-2243 2243: [SDOI2011]染色(树链剖分)

题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6267  Solved: 2291 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. Input 第一行包含