BZOJ 2243: [SDOI2011]染色 [树链剖分]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2243: [SDOI2011]染色 [树链剖分]相关的知识,希望对你有一定的参考价值。
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432
[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
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
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source
裸树链剖分
太愚蠢了我说怎么全WA最后发现建树时给线段树的节点分配颜色弄错了
线段树就是普通的颜色覆盖而已,注意两个重链之间判断颜色相同
加了那个普通的标记剪枝,就bzoj rank16了
// // main.cpp // sdoi2011染色 // // Created by Candy on 2016/12/14. // Copyright © 2016年 Candy. All rights reserved. // #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lc o<<1 #define rc o<<1|1 #define m ((l+r)>>1) #define lson o<<1,l,m #define rson o<<1|1,m+1,r const int N=1e5+5; int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f; } int n,Q,ww[N],w[N],x,y,a,b,c; char s[10]; struct edge{ int v,ne; }e[N<<1]; int h[N],cnt; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt; } int top[N],size[N],tid[N],tot,fa[N],deep[N],mx[N]; void dfs(int u){ size[u]++; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(v==fa[u]) continue; fa[v]=u;deep[v]=deep[u]+1; dfs(v); size[u]+=size[v]; if(size[v]>size[mx[u]]) mx[u]=v; } } void dfs(int u,int anc){ if(!u) return; tid[u]=++tot;top[u]=anc; dfs(mx[u],anc); for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa[u]&&e[i].v!=mx[u]) dfs(e[i].v,e[i].v); } struct node{ int lv,rv,cnt,tag; }t[N<<2]; inline void merge(int o){ t[o].tag=-1; t[o].lv=t[lc].lv; t[o].rv=t[rc].rv; t[o].cnt=t[lc].cnt+t[rc].cnt-(t[lc].rv==t[rc].lv); } inline void paint(int o,int v){ t[o].tag=t[o].lv=t[o].rv=v; t[o].cnt=1; } void build(int o,int l,int r){ if(l==r) paint(o,w[l]); else{ build(lson); build(rson); merge(o); } } inline void pushDown(int o){ if(t[o].tag!=-1){ paint(lc,t[o].tag); paint(rc,t[o].tag); t[o].tag=-1; } } void change(int o,int l,int r,int ql,int qr,int v){ if(ql<=l&&r<=qr) paint(o,v); else{ pushDown(o); if(ql<=m) change(lson,ql,qr,v); if(m<qr) change(rson,ql,qr,v); merge(o); } } int query(int o,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return t[o].cnt; else if(t[o].tag!=-1) return 1; else{ pushDown(o); int ans=0; if(ql<=m) ans+=query(lson,ql,qr); if(m<qr) ans+=query(rson,ql,qr); if(ql<=m&&m<qr&&t[lc].rv==t[rc].lv) ans--; return ans; } } int getcol(int o,int l,int r,int p){ if(l==r) return t[o].lv; else if(t[o].tag!=-1) return t[o].tag; else{ if(p<=m) return getcol(lson,p); else return getcol(rson,p); } } void sol1(int x,int y,int c){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); change(1,1,n,tid[top[x]],tid[x],c); x=fa[top[x]]; } if(tid[x]>tid[y]) swap(x,y); change(1,1,n,tid[x],tid[y],c); } int sol2(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); ans+=query(1,1,n,tid[top[x]],tid[x]); if(getcol(1,1,n,tid[top[x]])==getcol(1,1,n,tid[fa[top[x]]])) ans--; x=fa[top[x]]; } if(tid[x]>tid[y]) swap(x,y); ans+=query(1,1,n,tid[x],tid[y]); return ans; } int main(int argc, const char * argv[]) { n=read();Q=read(); for(int i=1;i<=n;i++) ww[i]=read(); for(int i=1;i<=n-1;i++) x=read(),y=read(),ins(x,y); dfs(1);dfs(1,1); for(int i=1;i<=n;i++) w[tid[i]]=ww[i]; build(1,1,n); while(Q--){ scanf("%s",s);a=read();b=read(); if(s[0]==‘C‘){ c=read();sol1(a,b,c); }else printf("%d\n",sol2(a,b)); } return 0; }
以上是关于BZOJ 2243: [SDOI2011]染色 [树链剖分]的主要内容,如果未能解决你的问题,请参考以下文章