題意:
給定一棵有n個節點的無根樹和m個操作,操作有2類:
1)將節點a到節點b路徑上所有點都染成顏色c;
2)詢問節點a到節點n路徑上的顏色段數量(連續相同顏色被認為是同一段),如「112221」由3段組成:「11」、「222」和「1」。
n, m <= 100000
思路:樹的形態沒有改變,用樹鏈剖分維護即可。
(pre1, suf1, tot1) + (pre2, suf2, tot2) = (pre1, suf2, tot1 + tot2 - (suf1 == pre2))
又複習了一遍樹剖,感覺細節比較多,寫的時候要想清楚。。。
#include
#include
#define for(i,j,k) for(int i = j;i <= (int)k;i++)
#define lc (h << 1), l, m
#define rc (h << 1 | 1), m+1, r
#define root 1, 1, n
#define m ((l + r) >> 1)
using
namespace
std;
int n, m;
const
int n = 100010;
int fa[n], id[n], top[n], co[n], c[n], sz[n], son[n], dep[n], e;
vector
g[n];
void dfs1(int h)
}void dfs2(int h)
}struct info;
}info operator + (const info& a) const;
}};struct segmenttree
void pushdown(int h, int l, int r)
}void create(int h, int l, int r), col[h] = c[l];
else
}void modify(int h, int l, int r, int l, int r, int v), col[h] = v;
else
}info query(int h, int l, int r, int l, int r)
}}t;void change(int u, int v, int val)
if(dep[u] > dep[v]) swap(u, v);
t.modify(root, id[u], id[v], val);
}int query(int u, int v);
int x = u, y = v;
while(top[x] != top[y])
while(u != x) l = t.query(root, id[top[u]], id[u]) + l, u = fa[top[u]];
while(v != y) r = t.query(root, id[top[v]], id[v]) + r, v = fa[top[v]];
if(dep[u] > dep[v]) return (l.rev() + t.query(1, 1, n, id[v], id[u]).rev() + r).tot;
else
return (l.rev() + t.query(root, id[u], id[v]) + r).tot;
}int main()
dfs1(1), dfs2(1);
t.create(1, 1, n);
while(m--)
return
0;}
SDOI2011 染色 樹鏈剖分
題目鏈結 有一棵n個節點的樹,每個節點有顏色,支援兩種操作 樹上的鏈操作擺明了要用樹鏈剖分.用線段樹來維護資訊.線段樹的每個節點需要儲存,區間的顏色數量,以及區間左端點的顏色和右端點的顏色.以下是線段樹中特殊操作 先把左右兒子的顏色段數加起來.如果左兒子的右端點和右兒子的左端點是同一種顏色,那麼顏色...
SDOI2011 染色 樹鏈剖分
輸入格式 輸出格式 對於每個詢問操作,輸出一行答案。輸入樣例 1 6 52 2 1 2 1 1 1 21 3 2 42 5 2 6q 3 5 c 2 1 1 q 3 5 c 5 1 2 q 3 5 輸出樣例 1 31 怎麼實現建樹操作呢,我們需要兩個陣列s和t,代表當前操作區間的左端點的顏色和右端點...
SDOI2011 染色 題解
題目大意 給定一棵有n個節點的無根樹和m個操作,操作有2類 1 將節點a到節點b路徑上所有點都染成顏色c 2 詢問節點a到節點b路徑上的顏色段數量 連續相同顏色被認為是同一段 思路 樹剖之後,維護其兩端的顏色 答案和標記即可。include include define n 100001 using...