1. 程式人生 > >洛谷 P2486 BZOJ 2243 [SDOI2011]染色

洛谷 P2486 BZOJ 2243 [SDOI2011]染色

技術分享 query i++ 連續 noi 語文 cnblogs sca 色相

題目描述

給定一棵有n個節點的無根樹和m個操作,操作有2類:

1、將節點a到節點b路徑上所有點都染成顏色c;

2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認為是同一段),如“112221”3段組成:“11”、“222”和“1”

請你寫一個程序依次完成這m個操作。

輸入輸出格式

輸入格式:

第一行包含2個整數n和m,分別表示節點數和操作數;

第二行包含n個正整數表示n個節點的初始顏色

下面 行每行包含兩個整數x和y,表示xy之間有一條無向邊。

下面 行每行描述一個操作:

“C a b c”表示這是一個染色操作,把節點a到節點b路徑上所有點(包括a和b)都染成顏色c;

“Q a b”表示這是一個詢問操作,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。

輸出格式:

對於每個詢問操作,輸出一行答案。

輸入輸出樣例

輸入樣例#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

解題思路

  樹剖套線段樹。這題重點在線段樹上。線段樹的每個節點存下此節點表示的區間範圍l、r,這個區間內顏色塊數num,l處的顏色lc,r處的顏色rc。

  然後從合並兩個區間的信息時,特判如果接口處顏色相同,則當前區間num等於兩個子區間num之和減一,不相等就不減一(語文不好,勉強看吧)

源代碼

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>

int n,m;

struct Edge{
    int next,to;
}e[
200010]; int head[100010]={0},cnt=1; void add(int u,int v) { e[cnt]={head[u],v}; head[u]=cnt++; } int color[100010]={0}; struct tree{ int fa; int w; int dep; int num_to; int wson; int top; int id; }t[100010]; void dfs1(int fa,int u,int dep) { t[u].fa=fa; t[u].dep=dep; t[u].num_to=1; t[u].wson=-1; int max_to=0,num_son=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==fa) continue; num_son++; dfs1(u,v,dep+1); int temp=t[v].num_to; t[u].num_to+=temp; if(temp>max_to) t[u].wson=v,max_to=temp; } } int id=1; void dfs2(int u,int top) { t[u].top=top; t[u].id=id; color[id]=t[u].w; id++; if(t[u].wson==-1) return; dfs2(t[u].wson,top); for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==t[u].fa||v==t[u].wson) continue; dfs2(v,v); } } struct stree{ int l,r; int lc,rc;//邊界l、r的顏色 int num;//區間內色塊數 }s[400010]; int lazy[400010]={0};//區間染色lazy void maketree(int x,int l,int r) { s[x].l=l,s[x].r=r; s[x].lc=color[l],s[x].rc=color[r]; if(l==r) { s[x].num=1; return; } int mid=l+r>>1; maketree(x<<1,l,mid); maketree(x<<1|1,mid+1,r); s[x].num=s[x<<1].num+s[x<<1|1].num-(s[x<<1].rc==s[x<<1|1].lc); } void pushdown(int x) { int ls=x<<1,rs=ls|1; s[rs].num=s[ls].num=1; s[ls].lc=s[ls].rc=s[rs].rc=s[rs].lc=lazy[ls]=lazy[rs]=lazy[x]; lazy[x]=0; } int query(int x,int l,int r) { if(l>s[x].r||r<s[x].l) return 0; if(l<=s[x].l&&s[x].r<=r) return s[x].num; if(lazy[x]) pushdown(x); int ans=query(x<<1,l,r)+query(x<<1|1,l,r); if(l<=s[x<<1].r&&r>=s[x<<1|1].l&&s[x<<1].rc==s[x<<1|1].lc) ans--; return ans; } int query_color(int x,int pos) { int l=s[x].l,r=s[x].r; if(l==r) return s[x].lc; int mid=l+r>>1; if(lazy[x]) pushdown(x); if(pos<=mid) return query_color(x<<1,pos); else return query_color(x<<1|1,pos); } void update(int x,int l,int r,int c) { if(l>s[x].r||r<s[x].l) return; if(l<=s[x].l&&s[x].r<=r) { lazy[x]=c; s[x].num=1; s[x].lc=s[x].rc=c; return; } if(lazy[x]) pushdown(x); update(x<<1,l,r,c),update(x<<1|1,l,r,c); s[x].lc=s[x<<1].lc; s[x].rc=s[x<<1|1].rc; s[x].num=s[x<<1].num+s[x<<1|1].num-(s[x<<1].rc==s[x<<1|1].lc); } void C(int x,int y,int c) { while(t[x].top!=t[y].top) { if(t[t[y].top].dep<t[t[x].top].dep) std::swap(x,y);//y的top更深 update(1,t[t[y].top].id,t[y].id,c); y=t[t[y].top].fa; } if(t[y].id<t[x].id) std::swap(x,y); update(1,t[x].id,t[y].id,c); } int Q(int x,int y) { int ans=0; while(t[x].top!=t[y].top) { if(t[t[y].top].dep>t[t[x].top].dep) std::swap(x,y);//x的top更深 ans+=query(1,t[t[x].top].id,t[x].id)-(query_color(1,t[t[x].top].id)==query_color(1,t[t[t[x].top].fa].id)); x=t[t[x].top].fa; } if(t[y].id<t[x].id) std::swap(x,y); ans+=query(1,t[x].id,t[y].id); return ans==0?1:ans; } int main() { //freopen("test.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&t[i].w); for(int i=1,u,v;i<n;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs1(0,1,1); dfs2(1,1); maketree(1,1,n); for(int i=1,a,b,c;i<=m;i++) { char mode[2]; scanf("%s",mode); if(mode[0]==Q) { scanf("%d%d",&a,&b); printf("%d\n",Q(a,b)); } else { scanf("%d%d%d",&a,&b,&c); C(a,b,c); } } return 0; }

洛谷 P2486 BZOJ 2243 [SDOI2011]染色