zoukankan      html  css  js  c++  java
  • 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并

    题目描述

    给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走。m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开始走,每个能走的格子最多只能经过一次,这个条件下能够走的最多格子数。

    输入

    第一行包含两个正整数n和m。第2行到第n行,每行包含两个正整数x和y,表示一条连接房间x和房间y的边。房间编
    号为1…n。接下来n行,每行包含两个字符。第n + k行表示房间k的两个区域,第一个字符为A区域,第二个字符为
    B区域。其中“.”(ASCII码为46)表示是薄冰块,“#”(ASCII码为35)表示是障碍物。最后的m行,每行一个操作:
    l C u s:将房间u里的两个区域修改为s。
    l Q u v:询问挑战者在房间u,馆主在房间v时,挑战者能与馆主进行挑战需要踩的冰块数。如果房间u的两个区域
    都是障碍物,那么输出0。
    N≤ 30 000
    M ≤ 80 000

    输出

    包含若干行,每行一个整数。即对于输入中的每个询问,依次输出一个答案。

    样例输入

    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(mlog^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
    " , solve(x , y));
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    结构与算法(04):排序规则与查找算法
    虚拟机系列 | JVM特点,基础结构与执行周期
    Springboot 轻量替代框架 Solon 1.3.10 发布
    Java RPC 框架 Solon 1.3.9 发布,更便利的支持
    Java RPC 框架 Solon 1.3.7 发布,增强Cloud接口能力范围
    分享个本地maven配置
    Java RPC 框架 Solon 1.3.1 发布,推出Cloud接口与配置规范
    使用 quartz-solon-plugin 开发定时任务(新)
    使用 cron4j-solon-plugin 开发定时任务(新)
    国际开源社区OW2成立快应用兴趣小组,助推快应用生态发展
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7725323.html
Copyright © 2011-2022 走看看