2325: [ZJOI2011]道馆之战

2325: [ZJOI2011]道馆之战

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 813  Solved: 309
[Submit][Status]

Description

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

三个冰地分别如下:

当走出第三个冰地之后,就可以与馆主进行道馆战了。

馆主发现这个难度太小,导致经常有挑战者能通过,为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一条路径相连,即这n个房间构成一个树状结构。

每个房间分成了A和B两个区域,每一区域都是一个薄冰块或者障碍物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)或这个房间的另一区域。

现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。

自从馆主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

Input

第一行包含两个正整数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。

Output

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

Sample Input

5 3

1 2

2 3

2 4

1 5

.#

..

#.

.#

..

Q 5 3

C 1 ##

Q 4 5

Sample Output

6

3

HINT

【样例说明】

第一个询问,从房间5出发经过的冰块数最多的路径为:

第二个询问,从房间4出发经过的冰块数最多的路径为:

【数据规模】

N≤ 30 000

M ≤ 80 000

Source

Day2

题目描述太蛋疼了……

总结一下就是一棵树上,每个点有a,b两个值,空地或者障碍,障碍就不能通过,同一个节点中a可以到b,但是a是障碍或者b是障碍就不行

询问从x到y,x从(a,b)两个点其中一个出发,最多能走多少个空地。即不要求能到达y,只求最多能走多少步

看了人家的题解,x[0..1][0..1]表示从左边的 左/右上角到 右边的 左/右上角 最多走多少步,即要求必须到达要走多少步

l[0..1]表示从左边 左/右上角出发能走多少步,r[0..1]同理

看update函数吧,不是特别麻烦,但是要注意细节

另外在树链剖分算答案的时候,由于你每条线段都是由根往下的

但x到y,从x到lca的路径是从下往上,lca到y的路径是从上往下,

也就是说求出的x到lca的路径,要反向!!!!!

妈的我只swap了l[0],r[0]和l[1]和r[1]

妈的还要swap x[0][1] 和x[1][0]啊啊啊啊啊啊!!!!调了一个半小时艹

/*
Author:wuhuajun
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define lson l, mid, rt << 1
#define rson mid+1, r, rt << 1 | 1
using namespace std;

typedef long long ll;
typedef double dd;
const int maxn=100010, INF = 1000000007;

int edge, n, fa[maxn], sz[maxn], son[maxn], dep[maxn], hash[maxn], top[maxn];
int h[maxn], num, a[maxn], x, y, tx, ty, Q, b[maxn];
char s[22], s1[22], s2[22];

struct Edge
{
    int to, ne;
} e[maxn * 2];

struct Seg
{
    int x[2][2], l[2], r[2];
    void clear()
    {
        x[0][0] = x[0][1] = x[1][0] = x[1][1] = 0;
        l[0] = l[1] = r[0] = r[1] = 0;
    }
} seg[maxn << 2], ans, c, L, R, ret;

void close()
{
    exit(0);
}

void addedge(int x,int y)
{
    e[edge].to = y;
    e[edge].ne = h[x];
    h[x] = edge++;
}

void dfs(int k,int from)
{
    sz[k] = 1;
    son[k] = 0;
    dep[k] = dep[from] + 1;
    for (int p=h[k];p!=-1;p=e[p].ne)
    {
        int to = e[p].to;
        if (from == to) continue;
        fa[to] = k;
        dfs(to, k);
        sz[k] += sz[to];
        if (sz[to] > sz[son[k]]) son[k] = to;
    }
}

void build(int k,int from)
{
    hash[k] = ++num;
    top[k] = from;
    if (son[k]) build(son[k], from);
    for (int p=h[k];p!=-1;p=e[p].ne)
    {
        int to = e[p].to;
        if (to != fa[k] && to != son[k])
            build(to, to);
    }
}

//{{{Segment部分

int cal(int x,int y)
{
    return max(-INF, max(x, y));
}

Seg operator + (Seg a,Seg b)
{
    if (a.x[0][0] == 0 && a.x[0][1] == 0 && a.x[1][0] == 0 && a.x[1][1] == 0 && a.l[0] == 0 && a.l[1] == 0 && a.r[0] == 0 && a.r[1] == 0)
        return b;
    if (b.x[0][0] == 0 && b.x[0][1] == 0 && b.x[1][0] == 0 && b.x[1][1] == 0 && b.l[0] == 0 && b.l[1] == 0 && b.r[0] == 0 && b.r[1] == 0)
        return a;
    c.x[0][0] = cal(a.x[0][0] + b.x[0][0], a.x[0][1] + b.x[1][0]);
    c.x[0][1] = cal(a.x[0][0] + b.x[0][1], a.x[0][1] + b.x[1][1]);
    c.x[1][0] = cal(a.x[1][0] + b.x[0][0], a.x[1][1] + b.x[1][0]);
    c.x[1][1] = cal(a.x[1][0] + b.x[0][1], a.x[1][1] + b.x[1][1]);
    c.l[0] = max(a.l[0], max(a.x[0][0] + b.l[0], a.x[0][1] + b.l[1]));
    c.l[1] = max(a.l[1], max(a.x[1][0] + b.l[0], a.x[1][1] + b.l[1]));
    c.r[0] = max(b.r[0], max(b.x[0][0] + a.r[0], b.x[1][0] + a.r[1]));
    c.r[1] = max(b.r[1], max(b.x[0][1] + a.r[0], b.x[1][1] + a.r[1]));
    return c;
}

void change(int L,int R,int val1,int val2,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        seg[rt].x[0][0] = seg[rt].l[0] = seg[rt].r[0] = val1;
        seg[rt].x[1][1] = seg[rt].l[1] = seg[rt].r[1] = val2;
        if (val1 == 1 && val2 == 1)
        {
            seg[rt].l[0] = seg[rt].l[1] = seg[rt].r[0] = seg[rt].r[1] = 2;
            seg[rt].x[0][1] = seg[rt].x[1][0] = 2;
        }
        else
        {
            seg[rt].x[0][1] = seg[rt].x[1][0] = -INF;
        }
        seg[rt].l[0] = max(seg[rt].l[0], 0);
        seg[rt].l[1] = max(seg[rt].l[1], 0);
        seg[rt].r[0] = max(seg[rt].r[0], 0);
        seg[rt].r[1] = max(seg[rt].r[1], 0);
        return;
    }
    int mid = (l + r) >> 1;
    if (L <= mid)
        change(L,R,val1,val2,lson);
    if (mid + 1 <= R)
        change(L,R,val1,val2,rson);
    seg[rt] = seg[rt << 1] + seg[rt << 1 | 1];
}

Seg query(int L,int R,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        return seg[rt];
    }
    int mid = (l + r) >> 1;
    Seg ans;
    ans.clear();
    if (L <= mid)
        ans = ans + query(L,R,lson);
    if (mid + 1 <= R)
        ans = ans + query(L,R,rson);
    return ans;
}
//}}}

Seg get_ans()
{
    tx = top[x];
    ty = top[y];
    L.clear();
    R.clear();
    while (tx != ty)
    {
        if (dep[tx] < dep[ty])
        {
            R = query(hash[ty], hash[y], 1, n, 1) + R;
            y = fa[ty];
            ty = top[y];
        }
        else
        {
            L = query(hash[tx], hash[x], 1, n, 1) + L;
            x = fa[tx];
            tx = top[x];
        }
    }
    if (dep[x] < dep[y])
    {
        R = query(hash[x], hash[y], 1, n, 1) + R;
    }
    else
    {
        L = query(hash[y], hash[x], 1, n, 1) + L;
    }
    swap(L.x[0][1], L.x[1][0]);
    swap(L.l[0], L.r[0]);
    swap(L.l[1], L.r[1]);
    return L + R;
}

void init()
{
    scanf("%d %d",&n,&Q);
    memset(h,-1,sizeof(h));
    for (int i=1;i<=n-1;i++)
    {
        scanf("%d %d",&x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    for (int i=1;i<=n;i++)
    {
        scanf("%s", s1);
        a[i] = s1[0] == ‘.‘ ? 1 : -INF;
        b[i] = s1[1] == ‘.‘ ? 1 : -INF;
    }
    dfs(1, 0);
    build(1, 1);
    /*
    for (int i=1;i<=n;i++)
    {
        printf("i:%d top:%d hash:%d\n",i, top[i], hash[i]);
    }
    */
    for (int i=1;i<=n;i++)
        change(hash[i], hash[i], a[i], b[i], 1, n, 1);
    while (Q--)
    {
        scanf("%s", s);
        if (s[0] == ‘Q‘)
        {
            scanf("%d %d",&x, &y);
            ret = get_ans();
            printf("%d\n", max(ret.l[0], ret.l[1]));
        }
        else
        {
            scanf("%d",&x);
            scanf("%s", s1);
            int t1 = s1[0] == ‘.‘ ? 1 : -INF;
            int t2 = s1[1] == ‘.‘ ? 1 : -INF;
            change(hash[x], hash[x], t1, t2, 1, n, 1);
        }
    }
}

int main ()
{
    init();
    close();
    return 0;
}

2325: [ZJOI2011]道馆之战,布布扣,bubuko.com

时间: 2024-10-10 14:22:31

2325: [ZJOI2011]道馆之战的相关文章

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

[BZOJ2325][ZJOI2011]道馆之战 Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开.三个冰地分别如下: 当走出第三个冰地之后,就可以与馆主进行道馆战了.馆主发现这个难度太小,导致经常有挑战者能通过,为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地.任意两个房间之间均有且仅有一条路径相

bzoj2325 [ZJOI2011]道馆之战

Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开. 三个冰地分别如下: 当走出第三个冰地之后,就可以与馆主进行道馆战了. 馆主发现这个难度太小,导致经常有挑战者能通过,为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地.任意两个房间之间均有且仅有一条路径相连,即这n个房间构成一个树状结构. 每个房间分

[ZJOI2011]道馆之战

Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开.三个冰地分别如下: 当走出第三个冰地之后,就可以与馆主进行道馆战了.馆主发现这个难度太小,导致经常有挑战者能通过,为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地.任意两个房间之间均有且仅有一条路径相连,即这n个房间构成一个树状结构.每个房间分成了A

bzoj千题计划243:bzoj2325: [ZJOI2011]道馆之战

http://www.lydsy.com/JudgeOnline/problem.php?id=2325 设线段树节点区间为[l,r] 每个节点维护sum[0/1][0/1]  从l的A/B区域到r的A/B区域 经过冰块的最大数量 mx[0][0] 从l的A区域出发向r经过冰块的最大数量 mx[0][1] 从l的B区域出发向r经过冰块的最大数量 mx[1][0] 从r的A区域出发向l经过冰块的最大数量 mx[1][1] 从r的B区域出发向l经过冰块的最大数量 #include<cstdio>

树链剖分 bzoj2325 [ZJOI2011]道馆之战

http://www.lydsy.com/JudgeOnline/problem.php?id=2325 吐槽一下部分分数据不满足性质 我打了6k的暴力.. 考虑一条链的情况 记录8个值 m[0/1][0/1]表示左边从哪里开始走 右边从哪里开始走(上面还是下面) 最多是多少 l[0/1] r[0/1]表示左边右边最多延伸多少 gss1的套路 然后大力树剖一发 小心各种细节 复杂度\(O(m \log n ^ 2)\) #include<bits/stdc++.h> #define int l

bzoj2325 [ZJOI2011]道馆之战 树链剖分+DP+类线段树最大字段和

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2325 题解 可以参考线段树动态维护最大子段和的做法. 对于线段树上每个节点 \(o\),维护 \(ls_{0/1}, rs_{0/1}, s_{0/1, 0/1}\) 分别表示从最左边的上面/下面的格子进入最多走的方块数量,从最右边的上面/下面的格子进入最多走的方块数量,从最左边的上面/下面到最右边的上面/下面的做多走的方块数量. 然后合并的时候也类似与线段树最大字段和.\(ls\) 的话保

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

As FancyCoder

路漫漫其修远兮,吾将上下而求索.搞OI的时候,我用这句话勉励自己. 漫漫六年OI路,无数个对着电脑屏幕的日日夜夜,无数次清脆急促的键盘敲击声,对OI的那份热爱给了我从未有过的执着. 有发自内心的高兴,有真真切切的泪水. 这个是我自己做的一份OI笔记吧.算是一份算法清单吧,外加一些题目的总结. 不过由于我水平有限,很多东西也不甚懂,所以可能不会特别全面. 不过觉得可能对后人有用,就放上来了.博君一笑. 还有部分自己的代码以及一份在学校里曾经用过的讲稿(自己感觉还是蛮好的).也顺便放上来了. 下面是

bzoj1146 [CTSC2008]网络管理Network

Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由