日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[ZJOI2011] 道馆之战(树链剖分)

發(fā)布時(shí)間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [ZJOI2011] 道馆之战(树链剖分) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

problem

luogu-P4679

理解清楚題意又是一個(gè)世紀(jì)的更迭了

給定一個(gè)樹,每個(gè)節(jié)點(diǎn)位置上實(shí)際放了兩個(gè)節(jié)點(diǎn)。

然后若干次修改和查詢。... 能走,#\## 不能走。

詢問 u→vu\rightarrow vuv 的簡單路徑上最長能走的距離。(是強(qiáng)制從 uuu 開始,不是問最長子段哦)

同個(gè)節(jié)點(diǎn)位置上放的兩個(gè)節(jié)點(diǎn)能否互通依舊遵循上面的規(guī)則。

solution

這種路徑問題通常我們考慮樹剖,如果涉及斷邊加邊的動(dòng)態(tài)操作就考慮 LCT\text{LCT}LCT

上樹鏈剖分的板子,兩個(gè) dfs\text{dfs}dfs duangduang掄上去。

然后考慮線段樹怎么維護(hù)信息能夠合并。

我們定義每個(gè)節(jié)點(diǎn)位置上實(shí)際存在的兩個(gè)節(jié)點(diǎn)分別為 0/10/10/1

線段樹上每個(gè)節(jié)點(diǎn)維護(hù)區(qū)間 [l,r][l,r][l,r] 的信息:

  • lx[2]:llx[2]:llx[2]:l0/10/10/1 節(jié)點(diǎn)開始能走的最長距離。

  • rx[2]:rrx[2]:rrx[2]:r0/10/10/1 節(jié)點(diǎn)開始能走的最長距離。

  • mx[2][2]:lmx[2][2]:lmx[2][2]:l0/10/10/1rrr0/10/10/1 的最長距離。

    一定是從 lll0/10/10/1 開始走,且全程不被阻擋地成功走到 rrr0/10/10/1 的距離。

這有點(diǎn)類似線段樹維護(hù)區(qū)間最大子段和的維護(hù)方式,但略有不同。

合并兩個(gè)區(qū)間的時(shí)候,也是類似線段樹維護(hù)區(qū)間最大子段和的做法。

  • lx[i]lx[i]lx[i]

    • 直接就是左兒子算的答案。lson→lx[i]lson\rightarrow lx[i]lsonlx[i]

    • 左兒子整個(gè)區(qū)間走完的最大值再加上右兒子的左端點(diǎn)位置上的某個(gè)節(jié)點(diǎn)開始往后走的最大值。

      但不清楚左兒子走到其右端點(diǎn)位置的哪個(gè)節(jié)點(diǎn)更優(yōu),需要枚舉,右兒子的左端點(diǎn)位置同理。

      lson→mx[i][j]+rson→lx[j]lson\rightarrow mx[i][j]+rson\rightarrow lx[j]lsonmx[i][j]+rsonlx[j]

  • rx[i]rx[i]rx[i]

    • 直接右兒子算的答案。rson→rx[i]rson\rightarrow rx[i]rsonrx[i]

    • 右兒子整個(gè)區(qū)間走完的最大值再加上左兒子區(qū)間右端點(diǎn)位置上的某個(gè)節(jié)點(diǎn)開始往前走的最大值。

      同理需要枚舉。

      rson→mx[i][j]+lson→lx[j]rson\rightarrow mx[i][j]+lson\rightarrow lx[j]rsonmx[i][j]+lsonlx[j]

  • mx[i][j]mx[i][j]mx[i][j]

    只能知道是從左兒子區(qū)間左端點(diǎn)位置的 iii 節(jié)點(diǎn)到右兒子區(qū)間右端點(diǎn)位置的 jjj 節(jié)點(diǎn)。

    但不清楚左兒子區(qū)間右端點(diǎn)位置的結(jié)束節(jié)點(diǎn)以及右兒子區(qū)間左端點(diǎn)位置的開始節(jié)點(diǎn),同樣需要枚舉。

    且左兒子結(jié)束節(jié)點(diǎn)應(yīng)與右兒子開始節(jié)點(diǎn)一樣,不然走不過去。

    lson→mx[i][k]+rson→mx[k][j]lson\rightarrow mx[i][k]+rson\rightarrow mx[k][j]lsonmx[i][k]+rsonmx[k][j]

合并知道了,單點(diǎn)修改應(yīng)該就能明白。這里不再贅述。可以看下面代碼。

只說一點(diǎn):因?yàn)橐B續(xù),所以如果是阻攔直接設(shè)成 ?∞-\infty?。 這樣子就一定不可能使兩段無法到達(dá)的區(qū)間答案在線段樹上被錯(cuò)誤合并。

最后需要注意一點(diǎn)。

我們樹剖是從上往下剖,也就是說線段樹上一個(gè) [l,r][l,r][l,r] 區(qū)間,對應(yīng)的是原樹上一條從上往下的鏈的信息。

但實(shí)際上我們應(yīng)該是 u→lca(u,v)→vu\rightarrow lca(u,v)\rightarrow vulca(u,v)v,在樹上是先往上走再往下走。

那么往上走的信息就需要反轉(zhuǎn)區(qū)間維護(hù)的信息。

所以樹剖就不能寫代碼簡化版(通過判斷 u,vu,vu,v 所在重鏈的深度決定是否需要交換 u,vu,vu,v

u,vu,vu,v 地位是不同的。

最后答案就是從 uuu 位置的兩個(gè)節(jié)點(diǎn)出發(fā)能走的最遠(yuǎn)距離的較大值,即 ans→lx[0/1]ans\rightarrow lx[0/1]anslx[0/1]

code

#include <bits/stdc++.h> using namespace std; #define maxn 50005 int n, m, cnt; vector < int > G[maxn]; char op[maxn][5]; int f[maxn], siz[maxn], dep[maxn], son[maxn], top[maxn], dfn[maxn], id[maxn];namespace SGT {struct node { int lx[2], rx[2], mx[2][2];node() {memset( lx, 0, sizeof( lx ) );memset( rx, 0, sizeof( rx ) );memset( mx, 0, sizeof( mx ) );} }t[maxn << 2];#define lson now << 1#define rson now << 1 | 1#define mid (l + r >> 1)node operator + ( node ls, node rs ) {node ans;memset( ans.mx, -0x3f, sizeof( ans.mx ) );for( int i = 0;i <= 1;i ++ )for( int j = 0;j <= 1;j ++ ) {ans.lx[i] = max( ans.lx[i], max( ls.lx[i], ls.mx[i][j] + rs.lx[j] ) );ans.rx[i] = max( ans.rx[i], max( rs.rx[i], rs.mx[j][i] + ls.rx[j] ) );for( int k = 0;k <= 1;k ++ )ans.mx[i][j] = max( ans.mx[i][j], ls.mx[i][k] + rs.mx[k][j] );}return ans;}node init( char *op ) {node ans;if( op[0] == '.' and op[1] == '.' ) {ans.lx[0] = ans.lx[1] = ans.rx[0] = ans.rx[1] = 2;ans.mx[0][0] = ans.mx[1][1] = 1;ans.mx[0][1] = ans.mx[1][0] = 2;}else if( op[0] == '.' or op[1] == '.' ) {int d = op[1] == '.';memset( ans.mx, -0x3f, sizeof( ans.mx ) );ans.lx[d] = ans.rx[d] = ans.mx[d][d] = 1;ans.lx[!d] = ans.rx[!d] = 0; }else {ans.lx[0] = ans.lx[1] = ans.rx[0] = ans.rx[1] = 0;memset( ans.mx, -0x3f, sizeof( ans.mx ) );}return ans;}void reverse( node &ans ) {swap( ans.lx[0], ans.rx[0] );swap( ans.lx[1], ans.rx[1] );swap( ans.mx[0][1], ans.mx[1][0] );}void modify( int now, int l, int r, int p ) {if( l == r ) { t[now] = init( op[id[l]] ); return; }if( p <= mid ) modify( lson, l, mid, p );else modify( rson, mid + 1, r, p );t[now] = t[lson] + t[rson];}node query( int now, int l, int r, int L, int R ) {if( L <= l and r <= R ) return t[now];if( R <= mid ) return query( lson, l, mid, L, R );else if( mid < L ) return query( rson, mid + 1, r, L, R );else return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );} }namespace Qtree {void dfs1( int u, int fa ) {f[u] = fa, siz[u] = 1, dep[u] = dep[fa] + 1;for( int v : G[u] ) {if( v == fa ) continue;else dfs1( v, u );siz[u] += siz[v];if( siz[v] > siz[son[u]] ) son[u] = v;}}void dfs2( int u, int t ) {id[dfn[u] = ++ cnt] = u, top[u] = t;if( son[u] ) dfs2( son[u], t );else return;for( int v : G[u] ) if( v ^ f[u] and v ^ son[u] ) dfs2( v, v );}int query( int x, int y ) {SGT :: node ans1, ans2, ans;while( top[x] ^ top[y] ) {if( dep[top[x]] > dep[top[y]] )ans1 = SGT :: query( 1, 1, n, dfn[top[x]], dfn[x] ) + ans1, x = f[top[x]];elseans2 = SGT :: query( 1, 1, n, dfn[top[y]], dfn[y] ) + ans2, y = f[top[y]];}if( dep[x] > dep[y] ) ans1 = SGT :: query( 1, 1, n, dfn[y], dfn[x] ) + ans1;else ans2 = SGT :: query( 1, 1, n, dfn[x], dfn[y] ) + ans2;reverse( ans1 );ans = ans1 + ans2;return max( ans.lx[0], ans.lx[1] );} }int main() {scanf( "%d %d", &n, &m );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}Qtree :: dfs1( 1, 0 );Qtree :: dfs2( 1, 1 );for( int i = 1;i <= n;i ++ ) {scanf( "%s", op[i] );SGT :: modify( 1, 1, n, dfn[i] );}char opt[5]; int u, v;while( m -- ) {scanf( "%s", opt );if( opt[0] == 'C' ) {scanf( "%d", &u );scanf( "%s", op[u] );SGT :: modify( 1, 1, n, dfn[u] );}else {scanf( "%d %d", &u, &v );printf( "%d\n", Qtree :: query( u, v ) );}}return 0; }

總結(jié)

以上是生活随笔為你收集整理的[ZJOI2011] 道馆之战(树链剖分)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。