BZOJ 2243: [SDOI2011]染色
阿新 • • 發佈:2018-05-24
chan 區間修改 hint AS 描述 targe scrip names log
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
2
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 b c”表示這是一個染色操作,把節點a到節點b路徑上所有點(包括a和b)都染成顏色c; “Q a b”表示這是一個詢問操作,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。Output
對於每個詢問操作,輸出一行答案。
Sample Input
6 52 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
31
2
HINT
數N<=10^5,操作數M<=10^5,所有的顏色C為整數且在[0, 10^9]之間。
思路:
顯然,這道題我們可以通過在整顆樹上架一顆線段樹、然後進行區間修改區間查詢的操作。而詢問a到b的路徑,顯然是a到lca(a,b)的路徑和 b到lca(a,b)的路徑的並。所以我們可以使用先樹鏈剖分再在剖分序列上架線段樹的方式維護這樣的連續區間。通過在dfs2的時候給每個點壓入隊列確定順序,再在LCA的時候對每段進行查詢,即可得到每次的答案;
至於線段樹的操作,本題顯然是一道區間合並的線段樹,我們可以維護如下三種信息:區間左端點顏色,區間右端點顏色、區間顏色段數目。在pushup時,若左子樹的右端點和右子樹的左端點顏色相同,則是同一段顏色,sum[p] = sum[ls]+sum[rs] - 1,否則是兩段顏色,不需要-1 。值得註意的是,本題的顏色範圍是[0,1e9],所以在打lazy_tag時,要註意laz的初始值,不能是0,。但是我選擇把所有輸入的顏色++,相當於區間平移,不會對答案產生影響。
另外,本題函數非常多,可以用結構體封裝以增加代碼清晰度,我選擇了用class封裝,但是可能會稍微慢一點。
代碼如下
#include <cstring> #include <cstdio> #include <algorithm> #include <iostream> #include <cctype> #define ls p<<1 #define rs ls|1 #define lson l,mid,ls #define rson mid+1,r,rs #define im int mid = (l + r) >> 1 using namespace std; const int N = 1100000; int son[N],siz[N],fa[N],top[N],dep[N]; int idx[N],idy[N],cnt2; int to[N<<1],next[N<<1],pval[N],head[N],cnt1; int n,m; class ReadIn { private: inline char nc() { static char buf[100000], *p1, *p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } public: inline int read() { int x=0;char ch=nc(); while(!isdigit(ch))ch=nc(); while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-‘0‘;ch=nc();} return x; } inline char getc() { char ch=nc(); while(isspace(ch))ch=nc(); return ch; } }Rd; class SegmentTree { private: int lft[N<<2],rft[N<<2],sum[N<<2],laz[N<<2]; void pushdown(int p) { if(!laz[p]) return ; else { sum[ls]=sum[rs]=1; lft[ls]=laz[ls]=rft[ls]= lft[rs]=laz[rs]=rft[rs]=laz[p]; } laz[p]=0; return; } void pushup(int p) { sum[p]=sum[ls]+sum[rs]; if(rft[ls]==lft[rs])sum[p]--; lft[p]=lft[ls]; rft[p]=rft[rs]; } public: void build(int l,int r,int p) { if(l==r) { lft[p]=rft[p]=pval[idy[l]]; sum[p]=1; return ; } im; build(lson); build(rson); pushup(p); return ; } int query(int l,int r,int p,int x,int y) { pushdown(p); if(x<=l&&y>=r) { return sum[p]; } im; if(y<=mid) return query(lson,x,y); else if(x>mid) return query(rson,x,y); else { int re = query(lson,x,y)+query(rson,x,y);; if(rft[ls]==lft[rs])re--; return re; } } void change(int l,int r,int p,int x,int y,int c) { if(x<=l&&y>=r) { laz[p]=c; sum[p]=1; lft[p]=rft[p]=laz[p]; return; } im; pushdown(p); if(x<=mid) change(lson,x,y,c); if(y>mid) change(rson,x,y,c); pushup(p); } int find(int l,int r,int p,int x) { pushdown(p); if(l==r) return lft[p]; im; if(x<=mid) return find(lson,x); else return find(rson,x); } }Tr; class TreeChainDissection { public: void dfs1(int p) { dep[p]=dep[fa[p]]+1; siz[p]=1; for (int i = head[p];i; i = next[i] ) { if(to[i] != fa[p]) { fa[to[i]]=p; dfs1(to[i]); siz[p]+=siz[to[i]]; if(siz[to[i]]>siz[son[p]]) son[p]=to[i]; } } } void dfs2(int p,int t) { idx[p]=++cnt2; idy[cnt2]=p; top[p]=t; if(son[p]) dfs2(son[p],t); for(int i=head[p];i;i=next[i]) if(to[i]!=fa[p]&&to[i]!=son[p]) dfs2(to[i],to[i]); } int lcaq(int a,int b) { int ans=0; while(top[a]!=top[b]) { if(dep[top[a]]>dep[top[b]])swap(a,b); int upc = Tr.find(1,n,1,idx[fa[top[b]]]); int doc = Tr.find(1,n,1,idx[top[b]]); ans+= Tr.query(1,n,1,idx[top[b]],idx[b]); if(upc==doc) ans--; //printf("%d\n",ans); b=fa[top[b]]; } if(dep[a]<dep[b])swap(a,b); ans+=Tr.query(1,n,1,idx[b],idx[a]); if(!ans)ans=1; return ans; } void lcac(int x,int y,int z) { while(top[x]!=top[y]) { if(dep[top[x]]>dep[top[y]])swap(x,y); Tr.change(1,n,1,idx[top[y]],idx[y],z); y=fa[top[y]]; } if(dep[x]<dep[y])swap(x,y); Tr.change(1,n,1,idx[y],idx[x],z); } }Tcd; class Pre { private: inline void add_edge(int a,int b) { to[++cnt1] = b; next[cnt1] = head[a]; head[a] = cnt1; to[++cnt1] = a; next[cnt1] = head[b]; head[b] = cnt1; } public: void init() { n=Rd.read(),m=Rd.read(); int i,x,y; for(i=1 ;i <=n; i++) pval[i] = Rd.read() + 1; for(i=1 ;i < n; i++) { x=Rd.read(),y=Rd.read(); add_edge(x,y); } } }Pr; void solve() { Tcd.dfs1(1); Tcd.dfs2(1,1); Tr.build(1,n,1); int i,x,y,z; char opt; for(i=1;i<=m;i++) { opt=Rd.getc(); if(opt==‘Q‘) { x=Rd.read(); y=Rd.read(); int ans=Tcd.lcaq(x,y); printf("%d\n",ans); } else { x=Rd.read(), y=Rd.read(), z=Rd.read(); Tcd.lcac(x,y,z+1); } } } int main() { Pr.init(); solve(); }
歡迎來原博客看看 >原文鏈接<
BZOJ 2243: [SDOI2011]染色