problem

luogu-P4679

理解清楚题意又是一个世纪的更迭了

给定一个树,每个节点位置上实际放了两个节点。

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

询问 u→vu\rightarrow vu→v 的简单路径上最长能走的距离。(是强制从 uuu 开始,不是问最长子段哦)

同个节点位置上放的两个节点能否互通依旧遵循上面的规则。

solution

这种路径问题通常我们考虑树剖,如果涉及断边加边的动态操作就考虑 LCT\text{LCT}LCT。

上树链剖分的板子,两个 dfs\text{dfs}dfs duangduang抡上去。

然后考虑线段树怎么维护信息能够合并。

我们定义每个节点位置上实际存在的两个节点分别为 0/10/10/1。

线段树上每个节点维护区间 [l,r][l,r][l,r] 的信息:

  • lx[2]:llx[2]:llx[2]:l 的 0/10/10/1 节点开始能走的最长距离。

  • rx[2]:rrx[2]:rrx[2]:r 的 0/10/10/1 节点开始能走的最长距离。

  • mx[2][2]:lmx[2][2]:lmx[2][2]:l 的 0/10/10/1 到 rrr 的 0/10/10/1 的最长距离。

    一定是从 lll 的 0/10/10/1 开始走,且全程不被阻挡地成功走到 rrr 的 0/10/10/1 的距离。

这有点类似线段树维护区间最大子段和的维护方式,但略有不同。

合并两个区间的时候,也是类似线段树维护区间最大子段和的做法。

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

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

    • 左儿子整个区间走完的最大值再加上右儿子的左端点位置上的某个节点开始往后走的最大值。

      但不清楚左儿子走到其右端点位置的哪个节点更优,需要枚举,右儿子的左端点位置同理。

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

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

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

    • 右儿子整个区间走完的最大值再加上左儿子区间右端点位置上的某个节点开始往前走的最大值。

      同理需要枚举。

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

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

    只能知道是从左儿子区间左端点位置的 iii 节点到右儿子区间右端点位置的 jjj 节点。

    但不清楚左儿子区间右端点位置的结束节点以及右儿子区间左端点位置的开始节点,同样需要枚举。

    且左儿子结束节点应与右儿子开始节点一样,不然走不过去。

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

合并知道了,单点修改应该就能明白。这里不再赘述。可以看下面代码。

只说一点:因为要连续,所以如果是阻拦直接设成 −∞-\infty−∞。 这样子就一定不可能使两段无法到达的区间答案在线段树上被错误合并。

最后需要注意一点。

我们树剖是从上往下剖,也就是说线段树上一个 [l,r][l,r][l,r] 区间,对应的是原树上一条从上往下的链的信息。

但实际上我们应该是 u→lca(u,v)→vu\rightarrow lca(u,v)\rightarrow vu→lca(u,v)→v,在树上是先往上走再往下走。

那么往上走的信息就需要反转区间维护的信息。

所以树剖就不能写代码简化版(通过判断 u,vu,vu,v 所在重链的深度决定是否需要交换 u,vu,vu,v)

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

最后答案就是从 uuu 位置的两个节点出发能走的最远距离的较大值,即 ans→lx[0/1]ans\rightarrow lx[0/1]ans→lx[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;
}

[ZJOI2011] 道馆之战(树链剖分)相关推荐

  1. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  2. 2325: [ZJOI2011]道馆之战 (树链剖分+线段树)

    https://www.zhihu.com/question/43785539 https://www.zhihu.com/question/43785539?eweh=67oo https://ww ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  4. bzoj2325 [ZJOI2011]道馆之战(树链剖分+线段树)

    Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个 ...

  5. 【BZOJ2325】[ZJOI2011]道馆之战 线段树+树链剖分

    [BZOJ2325][ZJOI2011]道馆之战 Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过 ...

  6. BZOJ2325: [ZJOI2011]道馆之战

    BZOJ2325: [ZJOI2011]道馆之战 某$ZOJ$上竟然是个权限题... 没钱氪金的穷$AFO$狗老泪纵横... 附上大美洛谷的题面: P4679 [ZJOI2011]道馆之战 题目描述 ...

  7. 【ZJOI2008】树的统计(树链剖分)

    传送门 Solution: 就是树链剖分入门题啦~ // luogu-judger-enable-o2 #include<bits/stdc++.h> #define N 30005 #d ...

  8. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  9. P1505 [国家集训队]旅游 树链剖分

    题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...

  10. 【模板】树链剖分 P3384

    题目链接 //部分转自:https://www.luogu.org/problemnew/solution/P3384 初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的. 知识点: 重 ...

最新文章

  1. 后端常用开源组件合集(持续更新中)
  2. Kali Linux 2016.2初体验使用总结
  3. Centos 7 添加新磁盘
  4. keepalived+haproxy(双主)+nginx(静态)+lamp(动态)部署phpBB
  5. Pycharm 输出中文或打印中文乱码现象的解决办法
  6. python 多条件 选择 算法_python部署python算法 - 快速寻找满足条件的两个数
  7. 贪吃蛇博弈算法python_算法应用实践:如何用Python写一个贪吃蛇AI
  8. nodejs 写c++插件的实例
  9. 百度地图城市代码CityID
  10. yalmip实用操作(1)
  11. 学习日记(三)利用Arduino读取加速度传感器信号并采用NRF24L01无线传输
  12. 思科里服务器的dns配置文件,cisco设置dns
  13. 学习zencart模板制作
  14. 50部青春励志微电影致我们不朽的青春理想
  15. 【存储知识】文件系统与硬盘存储(分区、格式化、挂载、inode、软链接与硬链接)
  16. 高性能平台设计——美团旅行结算平台实践
  17. NXP i.MX6Q 双屏同显hdmi显示闪烁解决方案
  18. 括弧匹配检验(括号匹配问题)
  19. Python图像识别及操作
  20. 使用javascript实现表单校验(聚焦onfocus()和离焦onblur()以及在指定位置输出innerHTML='')

热门文章

  1. MATLAB常用算法与应用实例分享来袭!
  2. 百度内部培训PPT流出:数据分析的道与术
  3. K-Means算法的10个有趣用例
  4. 从生物神经网络到人工神经网络
  5. oracle+查表物理块数,如何统计一段时间内 发生在某个表上的 物理读写的块数
  6. java proguard 使用_一步步教你使用Proguard混淆Java源代码
  7. python怎么安装开发版_python - easy_install的安装和使用
  8. jbl css-h15,JBL CSS8006BM 天花音箱
  9. 软件构造学习笔记-实验3
  10. 交换机千兆和百兆对网速影响_家里明明装了百兆宽带!为啥网速还这么慢?原因竟然在这!...