題意:
給出一棵樹,每個頂點上有個顏色\(c_i\)。
有兩種操作:
分析:首先樹鏈剖分,下面考慮線段樹部分:
我們維護乙個區間的左端點的顏色和右斷點的顏色以及該區間的顏色段數,在加乙個顏色覆蓋標記。
在pushup
的時候,如果左區間右端點顏色和右區間左端點顏色相同,那麼這段顏色可以合併,合併區間的顏色段數為左右子區間顏色段數之和減1;
否則,答案為左右子區間顏色段數之和。
#include #include #include using namespace std;
const int maxn = 100000 + 10;
const int maxnode = maxn * 4;
struct edge
edge(int v, int nxt):v(v), nxt(nxt) {}};
int n, m, a[maxn];
int ecnt, head[maxn];
edge edges[maxn * 2];
void addedge(int u, int v)
int fa[maxn], dep[maxn], sz[maxn], son[maxn];
int tot, top[maxn], id[maxn], pos[maxn];
void dfs(int u) }
void dfs2(int u, int tp) }
struct node
node(int l, int r, int c): lcol(l), rcol(r), cntv(c) {}};
void reverse(node& t)
node operator + (const node& a, const node& b)
int setv[maxnode];
node t[maxnode];
void build(int o, int l, int r)
int m = (l + r) / 2;
build(o<<1, l, m);
build(o<<1|1, m+1, r);
t[o] = t[o<<1] + t[o<<1|1];}
void pushdown(int o) }
void update(int o, int l, int r, int ql, int qr, int v)
pushdown(o);
int m = (l + r) / 2;
if(ql <= m) update(o<<1, l, m, ql, qr, v);
if(qr > m) update(o<<1|1, m+1, r, ql, qr, v);
t[o] = t[o<<1] + t[o<<1|1];}
void update(int u, int v, int val)
update(1, 1, n, id[t1], id[u], val);
u = fa[t1]; t1 = top[u];
}if(dep[u] > dep[v]) swap(u, v);
update(1, 1, n, id[u], id[v], val);}
node query(int o, int l, int r, int ql, int qr)
int query(int u, int v) else
}if(dep[u] > dep[v]) else
reverse(q2);
q1 = q1 + q2;
return q1.cntv;}
int main()
dfs(1);
tot = 0;
dfs2(1, 1);
build(1, 1, n);
char cmd[5];
int a, b, c;
while(m--) else
}return 0;
}
bzoj 2243 染色 樹鏈剖分
首先這是個挺裸的題,由於太久沒寫剖分導致調了好久,前天調了一下午,一直查不到錯 昨晚在看春晚的時候突然靈機一動,發現合併的時候出了問題,開電腦把它a掉了 感覺自己也蠻拼的給定 一棵有n 個節點的 無根樹和 m個操作 操作有 2類 1 將節點a 到節點b 路徑上所 有點都染 成顏色c 2 詢問節點a ...
bzoj 2243 樹鏈剖分 染色
time limit 20 sec memory limit 512 mb submit 3205 solved 1238 submit status discuss 給定一棵有n個節點的無根樹和m個操作,操作有2類 1 將節點a到節點b路徑上所有點都染成顏色c 2 詢問節點a到節點b路徑上的顏色段...
bzoj2243 樹鏈剖分 染色
description 給定一棵有n個節點的無根樹和m個操作,操作有2類 1 將節點a到節點b路徑上所有點都染成顏色c 2 詢問節點a到節點b路徑上的顏色段數量 連續相同顏色被認為是同一段 如 112221 由3段組成 11 222 和 1 請你寫乙個程式依次完成這m個操作。input 第一行包含2...