【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个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

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

Sample Output

3

1

2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

题解

直接树剖加线段树,维护区间颜色段数量,最左端颜色,最右端颜色,和覆盖标记。
对于x,y的操作转化为对于x,lca(x, y)和y,lca(x, y)的操作。
线段数在合并时注意如果左子区间的右端颜色和右子区间的左端颜色相同则减一。树链剖分是若当前重链顶和其父亲颜色相同再减一。最后查询的答案是将x,lca(x, y)和y,lca(x, y)的答案相加并直接减一。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
const int N = 100000 + 10, M = 200000 + 10;
int v[N];
int to[M], nxt[M], hd[N];
int dep[N], siz[N], bl[N], pos[N], fa[N], son[N], id[N];
int n, m, tot, sz;
struct Seg{
    int l, r;
}t[M<<1];
int cov[M<<1], l_cl[M<<1], r_cl[M<<1], sum[M<<1];

void insert(int u, int v){
    to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot;
    to[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot;
}
inline void in(int &x){
    x = 0; int f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    x *= f;
}
void init(){
    in(n); in(m);
    for(int i = 1; i <= n; i++) in(v[i]);
    for(int i = 1; i < n; i++){
        int x, y;
        in(x); in(y);
        insert(x, y);
    }
}
void dfs1(int x){
    siz[x] = 1;
    for(int i = hd[x]; i; i = nxt[i]){
        if(to[i] == fa[x]) continue;
        dep[to[i]] = dep[x] + 1;
        fa[to[i]] = x;
        dfs1(to[i]);
        if(siz[to[i]] > siz[son[x]]) son[x] = to[i];
        siz[x] += siz[to[i]];
    }
}
void dfs2(int x, int chain){
    pos[x] = ++sz;
    id[sz] = x;
    bl[x] = chain;
    if(!son[x]) return;
    dfs2(son[x], chain);
    for(int i = hd[x]; i; i = nxt[i])
        if(to[i] != fa[x] && to[i] != son[x])
            dfs2(to[i], to[i]);
}
int Lca(int x, int y){
    while(bl[x] != bl[y]){
        if(pos[bl[x]] < pos[bl[y]]) swap(x, y);
        x = fa[bl[x]];
    }
    return pos[x] < pos[y] ? x : y;
}

void pup(int o){
    l_cl[o] = l_cl[lc]; r_cl[o] = r_cl[rc];
    sum[o] = sum[lc] + sum[rc] - (r_cl[lc] == l_cl[rc]);
}
void pdw(int o){
    if(cov[o] == -1 || t[o].l == t[o].r) return;
    sum[lc] = sum[rc] = 1;
    cov[lc] = cov[rc] = cov[o];
    l_cl[lc] = r_cl[lc] = l_cl[rc] = r_cl[rc] = cov[o];
    cov[o] = -1;
}
void build(int o, int l, int r){
    t[o].l = l; t[o].r = r; sum[o] = 1; cov[o] = -1;
    if(l == r){
        l_cl[o] = r_cl[o] = cov[o] = v[id[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid); build(rc, mid+1, r);
    pup(o);
}
void change(int o, int x, int y, int c){
    pdw(o);
    int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
    if(l == x && r == y) { l_cl[o] = r_cl[o] = cov[o] = c; sum[o] = 1; return; }
    if(y <= mid) change(lc, x, y, c);
    else if(x > mid) change(rc, x, y, c);
    else change(lc, x, mid, c), change(rc, mid+1, y, c);
    pup(o);
}
int query(int o, int x, int y){
    pdw(o);
    int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
    if(l == x && r == y) return sum[o];
    if(y <= mid) return query(lc, x, y);
    else if(x > mid) return query(rc, x, y);
    else return query(lc, x, mid) + query(rc, mid+1, y) - (r_cl[lc] == l_cl[rc]);
}
int getc(int o, int x){
    pdw(o);
    int l = t[o].l, r = t[o].r, mid = (l + r) >> 1;
    if(l == r) return l_cl[o];
    if(x <= mid) return getc(lc, x);
    else return getc(rc, x);
}

int solvesum(int x, int f){
    int cnt = 0;
    while(bl[x] != bl[f]){
        cnt += query(1, pos[bl[x]], pos[x]) - (getc(1, pos[bl[x]]) == getc(1, pos[fa[bl[x]]]));
        x = fa[bl[x]];
    }
    cnt += query(1, pos[f], pos[x]);
    return cnt;
}
void solvechange(int x, int f, int c){
    while(bl[x] != bl[f]){
        change(1, pos[bl[x]], pos[x], c);
        x = fa[bl[x]];
    }
    change(1, pos[f], pos[x], c);
}
void work(){
    build(1, 1, n);
    char s[20];
    int a, b, c;
    for(int i = 1; i <= m; i++){
        scanf("%s", s);
        if(s[0] == 'C'){
            in(a); in(b); in(c);
            int t = Lca(a, b);
            solvechange(a, t, c);
            solvechange(b, t, c);
        }
        else{
            in(a); in(b);
            int t = Lca(a, b);
            printf("%d\n", solvesum(a, t) + solvesum(b, t) - 1);
        }
    }
}
int main(){
    init();
    dfs1(1);
    dfs2(1, 1);
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值