天天看点

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

2243: [SDOI2011]染色

Time Limit: 20 Sec Memory Limit: 512 MB

Submit: 7964 Solved: 2987

[Submit][Status][Discuss]

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]之间。

题解:树链剖分+线段树,注意每次查询时查询的是断断续续的区间,所以每次要继续下上一次区间的信息,如果两次区间的始末位置颜色相同的话,合并之后的颜色数就要-1。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int N = ;

int n,m;
int a[N],co[N];

struct node{
    int pre,v;
}edge[N];

int num=,head[N];
void addedge(int from,int to){
    num++;
    edge[num].pre=head[from];
    edge[num].v=to;
    head[from]=num;
}

int fa[N],dep[N];
int siz[N],son[N];

void dfs1(int u,int f,int d){
    siz[u]=,fa[u]=f,dep[u]=d;
    for(int i=head[u];i;i=edge[i].pre){
        int v=edge[i].v;
        if(v==f) continue;
        dfs1(v,u,d+);
        siz[u]+=siz[v];
        if(son[u]==-||siz[v]>siz[son[u]]) son[u]=v;
    }
}

int indx=;
int in[N],out[N],top[N];
void dfs2(int u,int tp){
    in[u]=out[u]=++indx;
    co[indx]=a[u];
    top[u]=tp;
    if(son[u]==-) return ;
    dfs2(son[u],tp);
    for(int i=head[u];i;i=edge[i].pre){
        int v=edge[i].v;
        if(v==son[u]||v==fa[u]) continue;
        dfs2(v,v);
    }
    out[u]=indx;
}

struct Node{
    int ans;
    int lx,rx;
    int l,r;
    int flag;
}t[N<<];

void update(int root){
    if(t[root<<].rx==t[root<<|].lx)
        t[root].ans=t[root<<].ans+t[root<<|].ans-;
    else t[root].ans=t[root<<].ans+t[root<<|].ans;
    t[root].lx=t[root<<].lx,t[root].rx=t[root<<|].rx;
}

void build(int root,int l,int r){
    t[root].l=l,t[root].r=r,t[root].flag=;
    if(l==r){
        t[root].ans=;
        t[root].lx=t[root].rx=co[l];
        return ;
    }
    int mid=l+r>>;
    build(root<<,l,mid);
    build(root<<|,mid+,r);
    update(root);
}

void pushdown(int root){
    int flag=t[root].flag,l=t[root].l,r=t[root].r;
    if(flag){
        t[root<<].ans=t[root<<|].ans=;
        t[root<<].lx=t[root<<].rx=flag;
        t[root<<|].lx=t[root<<|].rx=flag;
        t[root<<].flag=t[root<<|].flag=flag;
        t[root].flag=;
    }
}

void modify(int root,int pos,int val,int delta){
    int l=t[root].l,r=t[root].r;
    if(pos<=l&&val>=r){
        t[root].ans=;
        t[root].lx=t[root].rx=delta;
        t[root].flag=delta;
        return ;
    }
    int mid=l+r>>;
    pushdown(root);
    if(pos<=mid) modify(root<<,pos,val,delta);
    if(val>mid) modify(root<<|,pos,val,delta);
    update(root);
}

void modify(int u,int v,int delta){
    int f1=top[u],f2=top[v];
    while(f1!=f2){
        if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v);
        modify(,in[f1],in[u],delta);
        u=fa[f1],f1=top[u];
    }
    if(dep[u]>dep[v]) swap(u,v);
    modify(,in[u],in[v],delta);
}

int lc,rc;
int query(int root,int pos,int val,int L,int R){
    int l=t[root].l,r=t[root].r;
    if(l==L) lc=t[root].lx;
    if(r==R) rc=t[root].rx;
    if(pos==l&&val==r) return t[root].ans;
    int mid=l+r>>;
    pushdown(root);
    if(val<=mid) return query(root<<,pos,val,L,R);
    else if(pos>mid) return query(root<<|,pos,val,L,R);
    else{
        int a=query(root<<,pos,mid,L,R);
        int b=query(root<<|,mid+,val,L,R);
        if(t[root<<|].lx==t[root<<].rx) return a+b-;
        else return a+b;
    }
}

int query(int u,int v){
    int f1=top[u],f2=top[v];
    int sum=;
    int co1=-,co2=-;
    while(f1!=f2){
        if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v),swap(co1,co2);
        sum+=query(,in[f1],in[u],in[f1],in[u]);
        if(rc==co1) sum--;
        co1=lc;
        u=fa[f1];
        f1=top[u];
    }
    if(dep[u]<dep[v]) swap(u,v),swap(co1,co2);
    sum+=query(,in[v],in[u],in[v],in[u]);
    if(rc==co1) sum--;if(lc==co2) sum--;
    return sum;
}

#define ms(x,y) memset(x,y,sizeof(x))
int main(){
    ms(son,-);
    scanf("%d%d",&n,&m);
    for(register int i=;i<=n;i++) scanf("%d",&a[i]);
    for(register int i=;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);addedge(v,u);
    }
    dfs1(,,);dfs2(,);
    build(,,n);
    while(m--){
        char s[];
        int u,v,delta;
        scanf("%s",s);
        if(s[]=='C'){
            scanf("%d%d%d",&u,&v,&delta);
            modify(u,v,delta);
        }
        else{
           scanf("%d%d",&u,&v);
           printf("%d\n",query(u,v));
        }
    }
    return ;
}
           

7月60篇博客达成。这个月真是勤勉。

继续阅读