[树链剖分][SDOI 2011]染色,Housewife Wind
文章目錄
- T1:Housewife Wind
- 題目
- 題解
- code
- T2:染色
- 題目
- 題解
- code
今天選擇寫這篇博客主要是為了告訴大家一個(gè)道理,數(shù)組比vectorvectorvector快太多了,我這兩道題第一次都因?yàn)?span id="ozvdkddzhkzd" class="katex--inline">vectorvectorvector,TTT到飛起
T1:Housewife Wind
題目
After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional roads. We say that huts in the same pair directly connected. XX Village is so special that we can reach any other huts starting from an arbitrary hut. If each road cannot be walked along twice, then the route between every pair is unique.
Since Jiajia earned enough money, Wind became a housewife. Their children loved to go to other kids, then make a simple call to Wind: ‘Mummy, take me home!’
At different times, the time needed to walk along a road may be different. For example, Wind takes 5 minutes on a road normally, but may take 10 minutes if there is a lovely little dog to play with, or take 3 minutes if there is some unknown strange smell surrounding the road.
Wind loves her children, so she would like to tell her children the exact time she will spend on the roads. Can you help her?
Input
The first line contains three integers n, q, s. There are n huts in XX Village, q messages to process, and Wind is currently in hut s. n < 100001 , q < 100001.
The following n-1 lines each contains three integers a, b and w. That means there is a road directly connecting hut a and b, time required is w. 1<=w<= 10000.
The following q lines each is one of the following two types:
Message A: 0 u
A kid in hut u calls Wind. She should go to hut u from her current position.
Message B: 1 i w
The time required for i-th road is changed to w. Note that the time change will not happen when Wind is on her way. The changed can only happen when Wind is staying somewhere, waiting to take the next kid.
Output
For each message A, print an integer X, the time required to take the next child.
Sample Input
3 3 1
1 2 1
2 3 2
0 2
1 2 3
0 3
Sample Output
1
3
題解
其實(shí)這道題就是一個(gè)邊權(quán)模板題,這篇博客的重點(diǎn)是后面的染色
其次這道題我被卡了vectorvectorvector所以來記錄一下數(shù)組版怎么寫罷了vector版邊權(quán)模板
我覺得沒有什么講的必要,直接上就行了,如果剛剛踏入門的話,→移步入門樹鏈剖分
code
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define maxn 100005 struct noded {int u, v;int w;noded () {}noded ( int U, int V, int W ) {u = U;v = V;w = W;} }tmp[maxn]; struct EDGE {int to, next; }edge[maxn << 1]; int cnt = 1, n, q, s; int f[maxn], son[maxn], dep[maxn], Size[maxn]; int id[maxn], Top[maxn]; int tree[maxn << 2]; int head[maxn];void update ( int t, int l, int r, int idx, int val ) {if ( l == r ) {tree[t] = val;return;}int mid = ( l + r ) >> 1;if ( idx <= mid )update ( t << 1, l, mid, idx, val );elseupdate ( t << 1 | 1, mid + 1, r, idx, val );tree[t] = tree[t << 1] + tree[t << 1 | 1]; }int query ( int t, int l, int r, int L, int R ) {if ( L <= l && r <= R )return tree[t];int mid = ( l + r ) >> 1;int ans = 0;if ( L <= mid )ans += query ( t << 1, l, mid, L, R );if ( mid < R )ans += query ( t << 1 | 1, mid + 1, r, L, R );return ans; }void addedge ( int u, int v ) {edge[cnt].to = v;edge[cnt].next = head[u];head[u] = cnt ++; }void dfs1 ( int u, int fa, int depth ) {f[u] = fa;dep[u] = depth;Size[u] = 1;for ( int i = head[u];i != -1;i = edge[i].next ) {int v = edge[i].to;if ( v == fa )continue;dfs1 ( v, u, depth + 1 );Size[u] += Size[v];if ( Size[v] > Size[son[u]] || ! son[u] )son[u] = v;} }void dfs2 ( int u, int t ) {Top[u] = t;id[u] = ++ cnt;if ( ! son[u] )return;dfs2 ( son[u], t );for ( int i = head[u];i != -1;i = edge[i].next ) {int v = edge[i].to;if ( v != son[u] && v != f[u] )dfs2 ( v, v );} }int solve ( int x, int y ) {int ans = 0;int fx = Top[x], fy = Top[y];while ( fx != fy ) {if ( dep[fx] > dep[fy] ) {ans += query ( 1, 1, n, id[fx], id[x] );x = f[fx];fx = Top[x];}else {ans += query ( 1, 1, n, id[fy], id[y] );y = f[fy];fy = Top[y];}}if ( id[x] < id[y] )ans += query ( 1, 1, n, id[x] + 1, id[y] );elseans += query ( 1, 1, n, id[y] + 1, id[x] );return ans; }int main() {scanf ( "%d %d %d", &n, &q, &s );memset ( head, -1, sizeof ( head ) );for ( int i = 1;i < n;i ++ ) {scanf ( "%d %d %d", &tmp[i].u, &tmp[i].v, &tmp[i].w );addedge ( tmp[i].u, tmp[i].v );addedge ( tmp[i].v, tmp[i].u );}cnt = 0;//建邊的時(shí)候不小心用到了,一定要清零 dfs1 ( 1, 0, 1 );dfs2 ( 1, 0 );for ( int i = 1;i < n;i ++ ) {if ( dep[tmp[i].u] > dep[tmp[i].v] )swap ( tmp[i].u, tmp[i].v );update ( 1, 1, cnt, id[tmp[i].v], tmp[i].w );}int opt, x, w;for ( int i = 1;i <= q;i ++ ) {scanf ( "%d %d", &opt, &x );if ( opt ) {scanf ( "%d", &w );update ( 1, 1, n, id[tmp[x].v], w );}else {printf ( "%d\n", solve ( s, x ) );s = x;//注意接完孩子后,mom就待在了那里}}return 0; }T2:染色
題目
給定一棵有n個(gè)節(jié)點(diǎn)的無根樹和m個(gè)操作,操作有2類:
1、將節(jié)點(diǎn)a到節(jié)點(diǎn)b路徑上所有點(diǎn)都染成顏色c;
2、詢問節(jié)點(diǎn)a到節(jié)點(diǎn)b路徑上的顏色段數(shù)量(連續(xù)相同顏色被認(rèn)為是同一段),
如“112221”由3段組成:“11”、“222”和“1”。
請你寫一個(gè)程序依次完成這m個(gè)操作。
Input
第一行包含2個(gè)整數(shù)n和m,分別表示節(jié)點(diǎn)數(shù)和操作數(shù);
第二行包含n個(gè)正整數(shù)表示n個(gè)節(jié)點(diǎn)的初始顏色
下面 行每行包含兩個(gè)整數(shù)x和y,表示x和y之間有一條無向邊。
下面 行每行描述一個(gè)操作:
“C a b c”表示這是一個(gè)染色操作,把節(jié)點(diǎn)a到節(jié)點(diǎn)b路徑上所有點(diǎn)(包括a和b)都染成顏色c;
“Q a b”表示這是一個(gè)詢問操作,詢問節(jié)點(diǎn)a到節(jié)點(diǎn)b(包括a和b)路徑上的顏色段數(shù)量。
Output
對于每個(gè)詢問操作,輸出一行答案。
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
Sample Output
3
1
2
Hint
數(shù)N<=105N<=10^5N<=105,操作數(shù)M<=105M<=10^5M<=105,所有的顏色C為整數(shù)且在[0, 10^9]之間。
題解
其實(shí)這道題說難也不難,簡單也不簡單
首先這個(gè)是點(diǎn)權(quán)題,降低了一定難度,其次改顏色的操作也是模板,我們直接進(jìn)入如何統(tǒng)計(jì)顏色段數(shù)
可以知道當(dāng)兩個(gè)區(qū)間進(jìn)行合并的時(shí)候,交接處如果顏色相同的話,就并成了一段顏色,所以我們就要在線段樹時(shí)判斷,可以返回一個(gè)結(jié)構(gòu)體帶三個(gè)參數(shù)最左邊的顏色最右邊的顏色和顏色的段數(shù)
然后就是樹鏈剖分的時(shí)候我們要記錄上一次的左右顏色,分別于兩個(gè)點(diǎn)的左右進(jìn)行合并判斷,這里主要是考察碼力,可以直接看solvesolvesolve函數(shù),我稍微改變了一下寫法
code
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define maxn 100005 #define INF 0x7f7f7f7f struct node {//用vector太慢了 int next, v; }edge[maxn << 1]; struct noded {int lcolor, rcolor, sum; }tree[maxn << 2]; int head[maxn], tag[maxn << 2]; int cnt; int f[maxn], son[maxn], dep[maxn], Size[maxn]; int id[maxn], top[maxn]; int color[maxn];void addedge ( int x, int y ) {cnt ++;edge[cnt].next = head[x];edge[cnt].v = y;head[x] = cnt; }void pushdown ( int t ) {//不用lazy標(biāo)記要超時(shí) if ( ! tag[t] )return;tree[t << 1].lcolor = tree[t << 1].rcolor = tree[t << 1 | 1].lcolor = tree[t << 1 | 1].rcolor = tag[t];tag[t << 1] = tag[t << 1 | 1] = tag[t];tag[t] = 0;tree[t].sum = tree[t << 1].sum = tree[t << 1 | 1].sum = 1; }void update ( int t, int l, int r, int L, int R, int v ) {if ( L <= l && r <= R ) {tree[t].lcolor = tree[t].rcolor = tag[t] = v;tree[t].sum = 1;return;}pushdown ( t );int mid = ( l + r ) >> 1;if ( L <= mid )update ( t << 1, l, mid, L, R, v );if ( mid < R )update ( t << 1 | 1, mid + 1, r, L, R, v );tree[t].sum = tree[t << 1].sum + tree[t << 1 | 1].sum;if ( tree[t << 1].rcolor == tree[t << 1 | 1].lcolor )//判斷左右兒子的相接處是否顏色一樣 tree[t].sum --;tree[t].lcolor = tree[t << 1].lcolor;tree[t].rcolor = tree[t << 1 | 1].rcolor; }noded query ( int t, int l, int r, int L, int R ) {if ( L <= l && r <= R )return tree[t];int mid = ( l + r ) >> 1;pushdown ( t );if ( R <= mid )return query ( t << 1, l, mid, L, R );else if ( mid < L )return query ( t << 1 | 1, mid + 1, r, L, R );else {noded ans, ans1 = query ( t << 1, l, mid, L, R ), ans2 = query ( t << 1 | 1, mid + 1, r, L, R );ans.lcolor = ans1.lcolor;ans.rcolor = ans2.rcolor;ans.sum = ans1.sum + ans2.sum;if ( ans1.rcolor == ans2.lcolor )ans.sum --;return ans;} }void dfs1 ( int u, int fa, int depth ) {f[u] = fa;dep[u] = depth;Size[u] = 1;for ( int i = head[u];i != -1;i = edge[i].next ) {int v = edge[i].v;if ( v == fa )continue;dfs1 ( v, u, depth + 1 );Size[u] += Size[v];if ( Size[v] > Size[son[u]] || ! son[u] )son[u] = v;} }void dfs2 ( int u, int t ) {top[u] = t;id[u] = ++ cnt;if ( ! son[u] )return;dfs2 ( son[u], t );for ( int i = head[u];i != -1;i = edge[i].next ) {int v = edge[i].v;if ( v != son[u] && v != f[u] )dfs2 ( v, v );} }void solve ( int x, int y ) {int ans = 0, fx = top[x], fy = top[y];int xcolor = -1, ycolor = -1;noded ret;while ( fx != fy ) {if ( id[fx] < id[fy] ) {swap ( x, y );swap ( fx, fy );swap ( xcolor, ycolor );}ret = query ( 1, 1, cnt, id[fx], id[x] );ans += ret.sum;if ( ret.rcolor == xcolor )ans --;xcolor = ret.lcolor;x = f[fx];fx = top[x];}if ( id[x] > id[y] ) {swap ( x, y );swap ( xcolor, ycolor );}ret = query ( 1, 1, cnt, id[x], id[y] );ans += ret.sum;if ( xcolor == ret.lcolor )ans --;if ( ycolor == ret.rcolor )ans --;printf ( "%d\n", ans ); }void solve_update ( int x, int y, int c ) {int fx = top[x], fy = top[y];while ( fx != fy ) {if ( dep[fx] >= dep[fy] ) {update ( 1, 1, cnt, id[fx], id[x], c );x = f[fx];fx = top[x];}else {update ( 1, 1, cnt, id[fy], id[y], c );y = f[fy];fy = top[y];}}if ( id[x] <= id[y] )update ( 1, 1, cnt, id[x], id[y], c );elseupdate ( 1, 1, cnt, id[y], id[x], c ); }int main() {int n, m;memset ( head, -1, sizeof ( head ) );scanf ( "%d %d", &n, &m );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &color[i] );for ( int i = 1;i < n;i ++ ) {int a, b;scanf ( "%d %d", &a, &b );addedge ( a, b );addedge ( b, a );}cnt = 0;dfs1 ( 1, 0, 1 );dfs2 ( 1, 0 );for ( int i = 1;i <= n;i ++ )update ( 1, 1, cnt, id[i], id[i], color[i] );char opt[2];int a, b, c;for ( int i = 1;i <= m;i ++ ) {scanf ( "%s %d %d", opt, &a, &b );if ( opt[0] == 'C' ) {scanf ( "%d", &c );solve_update ( a, b, c );}else solve ( a, b );}return 0; }看不懂的歡迎評論
總結(jié)
以上是生活随笔為你收集整理的[树链剖分][SDOI 2011]染色,Housewife Wind的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [高斯消元及理论]线性方程组整数/浮点数
- 下一篇: 一般我们吃的零食西瓜子是夏天常吃的西瓜里