【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并
题目描述
输入
输出
包含若干行,每行一个整数。即对于输入中的每个询问,依次输出一个答案。
样例输入
5 3
1 2
2 3
2 4
1 5
.#
..
#.
.#
..
Q 5 3
C 1 ##
Q 4 5
样例输出
6
3
题解
树链剖分+线段树区间合并
首先显然不会往矩形的起点端移动(如果能移动则这一段一定可以由上下移动来替代)。
然后就可以进行树剖+区间合并。
对于线段树的某个节点,设$ls[0/1]$表示从左端的上/下位置开始走,最多能够走多少个格子。
那么考虑区间合并,如果只在左边则就是左儿子的$ls$,如果过到了右边的话则需要考虑是从上/下位置到的右边,还需要维护$ts[0/1][0/1]$表示从左端的上/下位置走到右端的上/下位置最多能走多少个格子。左边的$ts$加上右边的$ls$用于合并。
由于树剖需要区间翻转,因此还要维护$rs[0/1]$表示从右端的上/下位置开始走,最多能够走多少个格子。方法同理。
还需要维护$ts[0/1][0/1]$,此时对于每个值枚举中间位置,分中间走上/下两种情况讨论。
然后就是一堆乱七八糟的区间合并。难倒不难,就是强行循环展开的话代码量有点。。。
树剖时直接把x的(向上)和y的(向下)两种的处理出来,把x反过来与y合并即可。
时间复杂度$O(m\log^2n·常数)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 30010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
struct data
{
int ls[2] , rs[2] , ts[2][2];
data()
{
memset(ls , 0 , sizeof(ls));
memset(rs , 0 , sizeof(rs));
memset(ts , 0 , sizeof(ts));
ts[0][1] = ts[1][0] = -1 << 30;
}
data(int *v)
{
if(v[0] && v[1]) ls[0] = ls[1] = rs[0] = rs[1] = ts[0][1] = ts[1][0] = 2 , ts[0][0] = ts[1][1] = 1;
else if(v[0]) ls[0] = rs[0] = ts[0][0] = 1 , ls[1] = rs[1] = 0 , ts[0][1] = ts[1][0] = ts[1][1] = -1 << 30;
else if(v[1]) ls[1] = rs[1] = ts[1][1] = 1 , ls[0] = rs[0] = 0 , ts[0][0] = ts[0][1] = ts[1][0] = -1 << 30;
else ls[0] = ls[1] = rs[0] = rs[1] = 0 , ts[0][1] = ts[1][0] = ts[0][0] = ts[1][1] = -1 << 30;
}
friend data operator+(const data &a , const data &b)
{
data ans;
ans.ls[0] = max(a.ls[0] , max(a.ts[0][0] + b.ls[0] , a.ts[0][1] + b.ls[1]));
ans.ls[1] = max(a.ls[1] , max(a.ts[1][0] + b.ls[0] , a.ts[1][1] + b.ls[1]));
ans.rs[0] = max(b.rs[0] , max(b.ts[0][0] + a.rs[0] , b.ts[1][0] + a.rs[1]));
ans.rs[1] = max(b.rs[1] , max(b.ts[0][1] + a.rs[0] , b.ts[1][1] + a.rs[1]));
ans.ts[0][0] = max(-1 << 30 , max(a.ts[0][0] + b.ts[0][0] , a.ts[0][1] + b.ts[1][0]));
ans.ts[0][1] = max(-1 << 30 , max(a.ts[0][0] + b.ts[0][1] , a.ts[0][1] + b.ts[1][1]));
ans.ts[1][0] = max(-1 << 30 , max(a.ts[1][0] + b.ts[0][0] , a.ts[1][1] + b.ts[1][0]));
ans.ts[1][1] = max(-1 << 30 , max(a.ts[1][0] + b.ts[0][1] , a.ts[1][1] + b.ts[1][1]));
return ans;
}
data operator-()const
{
data ans;
ans.ls[0] = rs[0] , ans.ls[1] = rs[1];
ans.rs[0] = ls[0] , ans.rs[1] = ls[1];
ans.ts[0][0] = ts[0][0] , ans.ts[0][1] = ts[1][0];
ans.ts[1][0] = ts[0][1] , ans.ts[1][1] = ts[1][1];
return ans;
}
}a[N << 2];
int n , v[N][2] , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , deep[N] , si[N] , bl[N] , pos[N] , val[N] , tot;
char str[5];
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs1(int x)
{
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x])
fa[to[i]] = x , deep[to[i]] = deep[x] + 1 , dfs1(to[i]) , si[x] += si[to[i]];
}
void dfs2(int x , int c)
{
int i , k = 0;
bl[x] = c , pos[x] = ++tot , val[tot] = x;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && si[to[i]] > si[k])
k = to[i];
if(k)
{
dfs2(k , c);
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && to[i] != k)
dfs2(to[i] , to[i]);
}
}
inline void read(int *v)
{
scanf("%s" , str) , v[0] = (str[0] == '.') , v[1] = (str[1] == '.');
}
void build(int l , int r , int x)
{
if(l == r)
{
a[x] = data(v[val[l]]);
return;
}
int mid = (l + r) >> 1;
build(lson) , build(rson);
a[x] = a[x << 1] + a[x << 1 | 1];
}
void update(int p , int l , int r , int x)
{
if(l == r)
{
a[x] = data(v[val[l]]);
return;
}
int mid = (l + r) >> 1;
if(p <= mid) update(p , lson);
else update(p , rson);
a[x] = a[x << 1] + a[x << 1 | 1];
}
data query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return a[x];
int mid = (l + r) >> 1;
if(e <= mid) return query(b , e , lson);
else if(b > mid) return query(b , e , rson);
else return query(b , e , lson) + query(b , e , rson);
}
int solve(int x , int y)
{
data vx , vy;
while(bl[x] != bl[y])
{
if(deep[bl[x]] > deep[bl[y]]) vx = query(pos[bl[x]] , pos[x] , 1 , n , 1) + vx , x = fa[bl[x]];
else vy = query(pos[bl[y]] , pos[y] , 1 , n , 1) + vy , y = fa[bl[y]];
}
if(deep[x] > deep[y]) vx = query(pos[y] , pos[x] , 1 , n , 1) + vx;
else vy = query(pos[x] , pos[y] , 1 , n , 1) + vy;
vx = -vx + vy;
return max(vx.ls[0] , vx.ls[1]);
}
int main()
{
int m , i , x , y;
scanf("%d%d" , &n , &m);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
for(i = 1 ; i <= n ; i ++ ) read(v[i]);
dfs1(1) , dfs2(1 , 1);
build(1 , n , 1);
while(m -- )
{
scanf("%s%d" , str , &x);
if(str[0] == 'C') read(v[x]) , update(pos[x] , 1 , n , 1);
else scanf("%d" , &y) , printf("%d\n" , solve(x , y));
}
return 0;
}
【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并的更多相关文章
- BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树
题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
随机推荐
- win10家庭版升级为win10专业版
windows10 升级钥匙: DR9VN-GF3CR-RCWT2-H7TR8-82QGT 亲测可用
- JavaSE 第二次学习随笔(四)
---------------------------------------------------------------------------------------------------- ...
- Java学习笔记十二:Java中方法的重载
Java中方法的重载 什么是方法的重载呢? 如果同一个类中包含了两个或两个以上方法名相同.方法参数的个数.顺序或类型不同的方法,则称为方法的重载,也可称该方法被重载了.如下所示 4 个方法名称都为 s ...
- CERC2017 Gambling Guide,最短路变形,期望dp
题意 给定一个无向图,你需要从1点出发到达n点,你在每一点的时候,使用1个单位的代价,随机得到相邻点的票,但是你可以选择留在原地,也可以选择使用掉这张票,问到达n点的最小代价的方案的期望是多少. 分析 ...
- ActivityStream是什么?什么是Feed流?
我先说说feed流吧,它就是社交网站中用户活动信息流,例如用户写了博客.发了照片.评论了什么等等.Facebook叫newsFeed.推特叫TimeLineFeed.ActivityStream是这些 ...
- CentOS 7 systemd添加自定义系统服务
systemd: CentOS 7的服务systemctl脚本存放在:/usr/lib/systemd/,有系统(system)和用户(user)之分,即:/usr/lib/systemd/syste ...
- P2347 砝码称重
P2347 砝码称重 题目描述 设有1g.2g.3g.5g.10g.20g的砝码各若干枚(其总重<=1000), 输入输出格式 输入格式: 输入方式:a1 a2 a3 a4 a5 a6 (表示1 ...
- Django信号的使用
https://www.cnblogs.com/renpingsheng/p/7566647.html
- es6严格模式需要注意的地方
1.块级函数 "use strict"; if (true) { function f() { } // 语法错误 } es5中严格模式下禁止声明块级函数,而在es6的严格模式中可 ...
- OpenCV入门:(五:更改图片对比度和亮度)
1. 理论 图片的转换就是将图片中的每个像素点经过一定的变换,得到新像素点,新像素点组合成一张新的图片. 改变图片对比度和亮度的变换如下: 其中α和β被称作增益参数(gain parameter)和偏 ...