[树链剖分][SDOI 2011]染色,Housewife Wind
文章目錄
- T1:Housewife Wind
- 題目
- 題解
- code
- T2:染色
- 題目
- 題解
- code
今天選擇寫這篇博客主要是為了告訴大家一個道理,數組比vectorvectorvector快太多了,我這兩道題第一次都因為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
題解
其實這道題就是一個邊權模板題,這篇博客的重點是后面的染色
其次這道題我被卡了vectorvectorvector所以來記錄一下數組版怎么寫罷了vector版邊權模板
我覺得沒有什么講的必要,直接上就行了,如果剛剛踏入門的話,→移步入門樹鏈剖分
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;//建邊的時候不小心用到了,一定要清零 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個節點的無根樹和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 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
數N<=105N<=10^5N<=105,操作數M<=105M<=10^5M<=105,所有的顏色C為整數且在[0, 10^9]之間。
題解
其實這道題說難也不難,簡單也不簡單
首先這個是點權題,降低了一定難度,其次改顏色的操作也是模板,我們直接進入如何統計顏色段數
可以知道當兩個區間進行合并的時候,交接處如果顏色相同的話,就并成了一段顏色,所以我們就要在線段樹時判斷,可以返回一個結構體帶三個參數最左邊的顏色最右邊的顏色和顏色的段數
然后就是樹鏈剖分的時候我們要記錄上一次的左右顏色,分別于兩個點的左右進行合并判斷,這里主要是考察碼力,可以直接看solvesolvesolve函數,我稍微改變了一下寫法
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標記要超時 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; }看不懂的歡迎評論
總結
以上是生活随笔為你收集整理的[树链剖分][SDOI 2011]染色,Housewife Wind的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [高斯消元及理论]线性方程组整数/浮点数
- 下一篇: 一般我们吃的零食西瓜子是夏天常吃的西瓜里