BZOJ 2243 染色(樹鏈剖分好題)

2022-02-27 10:16:39 字數 3031 閱讀 4226

time limit: 20 sec  memory limit: 512 mb

submit: 7971  solved: 2990

[submit][status][discuss]

給定一棵有

n個節點的無根樹和

m個操作,操作有2類:

1、將節點

a到節點

b路徑上所有點都染成顏色c;

2、詢問節點

a到節點

b路徑上的顏色段數量(連續相同顏色被認為是同一段),如「

112221」由

3段組成:「11」

、「222」和「

1」。

請你寫乙個程式依次完成這

m個操作。

第一行包含

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)路徑上的顏色段數量。

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

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 531

2數n<=10^5,運算元m<=10^5,所有的顏色c為整數且在[0, 10^9]之間。

做了幾道普通的樹鏈剖分維護邊權、點權,查詢路徑的題目,感覺並沒有什麼特點,然而這題比較有意思,求路徑上連續顏色有幾段,顯然用線段樹的話只要維護當前區間最左和最右的顏色,左右子區間即可推出父區間的答案:左邊段數+右邊段數-(左區間右端點顏色==右區間左端點顏色)。然後統計的時候也要利用這個思想——線段樹的query與樹鏈剖分中記錄u與v上公升區間段數的同時也與u、v最後上公升的區間最左端點顏色比較得到答案。

**:

#include using namespace std;

#define inf 0x3f3f3f3f

#define lc(x) (x<<1)

#define rc(x) ((x<<1)+1)

#define mid(x,y) ((x+y)>>1)

#define fin(name) freopen(name,"r",stdin)

#define fout(name) freopen(name,"w",stdout)

#define clr(arr,val) memset(arr,val,sizeof(arr))

#define fast_io ios::sync_with_stdio(false);cin.tie(0);

typedef pairpii;

typedef long long ll;

const double pi = acos(-1.0);

const int n = 100010;

struct seg

;struct edge

edge(int _to, int _nxt): to(_to), nxt(_nxt) {}

};edge e[n << 1];

seg t[n << 2];

int head[n], tot;

int sz[n], fa[n], son[n], top[n], dep[n], idx[n], ts;

int arr[n];

int rc, lc;

void init()

void add(int s, int t)

void dfs1(int u, int f, int d)

}}void dfs2(int u, int tp)

}void pushup(int k)

void pushdown(int k)

void build(int k, int l, int r)

void update(int k, int l, int r, int c)

else

pushup(k);

}}int query(int k, int l, int r, int l, int r)

}int find(int u, int v)

ret += query(1, idx[tu], idx[u], idx[tu], idx[u]);

if (rc == last_u)

--ret;

last_u = lc;

u = fa[tu];

tu = top[u];

}if (dep[u] > dep[v])

ret += query(1, idx[u], idx[v], idx[u], idx[v]);

if (lc == last_u)

--ret;

if (rc == last_v)

--ret;

return ret;

}void solve(int u, int v, int c)

update(1, idx[tu], idx[u], c);

u = fa[tu];

tu = top[u];

}if (dep[u] > dep[v])

swap(u, v);

update(1, idx[u], idx[v], c);

}int main(void)

dfs1(1, 0, 1);

dfs2(1, 1);

build(1, 1, n);

for (i = 1; i <= n; ++i)

update(1, idx[i], idx[i], arr[i]);

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...