bzoj2325 [ZJOI2011]道馆之战

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

原来以为做完一条链的弱化版cf413E 这个应该很简单的

结果写了一天整整7500+B的代码快跪了

这题比cf那题更猥琐了一点,首先要输出路径长的最大值,这还比较简单

但是如果不能到达还要输出最多能走过的格子个数!这简直是增加代码量

用线段树维护八个东西。

对于区间[l,r]:

记录l的第一房间到r的第一房间的最长路a_to_a

记录l的第一房间到r的第二房间的最长路a_to_b

记录l的第二房间到r的第一房间的最长路b_to_a

记录l的第二房间到r的第二房间的最长路b_to_b

记录从l的第一房间出发,不一定要穿过[l,r]区间能走出的最长距离mxl1
记录从l的第二房间出发,不一定要穿过[l,r]区间能走出的最长距离mxl2

记录从r的第一房间出发,不一定要穿过[l,r]区间能走出的最长距离mxr1

记录从r的第一房间出发,不一定要穿过[l,r]区间能走出的最长距离mxr2

区间合并yy一下吧……实在想不出来就戳下面的代码(缩完代码也就30多行)、

它要求的是x->lca->y的路径,所以求出了x到lca的区间之后要翻转过来,才能拼在一起

处理的时候还要注意merge(seg1,seg2)时候一定要把记录答案的ans放在seg2的位置上。因为线段树中的区间顺序都是从根到叶节点方向的,做树链剖分的时候是从下往上找,每次这个区间都要直接接在ans的头上

#include<cstdio>
#include<iostream>
#define LL long long
#define inf 0x7ffffff
#define pa pair<int,int>
#define pi 3.1415926535897932384626433832795028841971
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m,cnt,tt,x0,y0,x1,y1;
struct segtree{
    int l,r;
    int a_to_a,a_to_b,b_to_a,b_to_b;
    int mxl1,mxl2,mxr1,mxr2;
}tree[2000010];
struct edge{
    int to,next;
}e[500010];
int head[200010];
segtree query;
bool mrk[200010],mrkl[200010],mrkr[200010];
int fa[200010][20],depth[200010],son[200010];
int chain[200010],belong[200010],place[200010],pplace[200010];
inline int max(int a,int b,int c)
{
	if (b>a)a=b;
	if (c>a)a=c;
	return a;
}
inline int max(int a,int b,int c,int d,int e,int f)
{
    if (b>a)a=b;
    if (c>a)a=c;
    if (d>a)a=d;
    if (e>a)a=e;
    if (f>a)a=f;
    return a;
}
inline void ins(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
inline void insert(int u,int v)
{
    ins(u,v);
    ins(v,u);
}
inline void dfs1(int x,int dep)
{
    if (mrk[x])return;mrk[x]=1;
    son[x]=1;depth[x]=dep;
    for (int i=1;i<20;i++)
      fa[x][i]=fa[fa[x][i-1]][i-1];
    for (int i=head[x];i;i=e[i].next)
      if (!mrk[e[i].to])
      {
        fa[e[i].to][0]=x;
        dfs1(e[i].to,dep+1);
        son[x]+=son[e[i].to];
      }
}
inline void dfs2(int x,int chain)
{
    place[x]=++tt;pplace[tt]=x;
    belong[x]=chain;
    int mx=-1,res=-1;
    for (int i=head[x];i;i=e[i].next)
      if (e[i].to!=fa[x][0])
        {
            if (son[e[i].to]>mx)
            {
                mx=son[e[i].to];
                res=e[i].to;
            }
        }
    if (res==-1)return;
    dfs2(res,chain);
    for (int i=head[x];i;i=e[i].next)
      if (res!=e[i].to&&fa[x][0]!=e[i].to)
      dfs2(e[i].to,e[i].to);
}
inline int LCA(int x,int y)
{
    if (depth[x]<depth[y])swap(x,y);
    int res=depth[x]-depth[y];
    for (int i=0;i<20;i++)
      if (res & (1<<i))x=fa[x][i];
    for (int i=19;i>=0;i--)
      if (fa[x][i]!=fa[y][i])
        {
            x=fa[x][i];
            y=fa[y][i];
        }
    if (x==y)return x;
    return fa[x][0];
}
inline void ref(int a,int b,int &c)
{
	if (a!=-1&&b!=-1)c=max(c,a+b);
}
segtree merge(segtree a,segtree b)
{
	if (a.l==0)return b;
	if (b.l==0)return a;
    segtree k;
    k.a_to_a=k.a_to_b=k.b_to_a=k.b_to_b=-1;
    k.mxl1=a.mxl1;
    k.mxl2=a.mxl2;
    k.mxr1=b.mxr1;
    k.mxr2=b.mxr2;
    k.l=min(a.l,b.l); k.r=max(a.r,b.r);
    ref(a.a_to_a,b.a_to_a,k.a_to_a);
    ref(a.a_to_b,b.b_to_a,k.a_to_a);
    ref(a.a_to_a,b.a_to_b,k.a_to_b);
    ref(a.a_to_b,b.b_to_b,k.a_to_b);
    ref(a.b_to_a,b.a_to_a,k.b_to_a);
    ref(a.b_to_b,b.b_to_a,k.b_to_a);
    ref(a.b_to_a,b.a_to_b,k.b_to_b);
    ref(a.b_to_b,b.b_to_b,k.b_to_b);
    ref(a.a_to_a,b.mxl1,k.mxl1);
    ref(a.a_to_b,b.mxl2,k.mxl1);
    ref(a.b_to_a,b.mxl1,k.mxl2);
    ref(a.b_to_b,b.mxl2,k.mxl2);
    ref(a.mxr1,b.a_to_a,k.mxr1);
    ref(a.mxr1,b.a_to_b,k.mxr2);
    ref(a.mxr2,b.b_to_a,k.mxr1);
    ref(a.mxr2,b.b_to_b,k.mxr2);
    return k;
}
inline void buildtree(int now,int l,int r)
{
    tree[now].l=l;tree[now].r=r;
    if (l==r)
    {
        tree[now].a_to_a=tree[now].a_to_b=tree[now].b_to_a=tree[now].b_to_b=-1;
        tree[now].mxl1=tree[now].mxl2=tree[now].mxr1=tree[now].mxr2=-1;
        if (mrkl[pplace[l]])tree[now].a_to_a=1,tree[now].mxl1=tree[now].mxr1=1;
        if (mrkr[pplace[l]])tree[now].b_to_b=1,tree[now].mxl2=tree[now].mxr2=1;
        if (mrkl[pplace[l]]&&mrkr[pplace[l]])
        {
            tree[now].a_to_b=2;
            tree[now].b_to_a=2;
            tree[now].mxl1=tree[now].mxl2=2;
            tree[now].mxr1=tree[now].mxr2=2;
        }
        return;
    }
    int mid=(l+r)>>1;
    buildtree(now<<1,l,mid);
    buildtree(now<<1|1,mid+1,r);
    tree[now]=merge(tree[now<<1],tree[now<<1|1]);
}
inline segtree ask_in_tree(int now,int x,int y)
{
    int l=tree[now].l,r=tree[now].r;
    if (l==x&&r==y)return tree[now];
    int mid=(l+r)>>1;
    if (y<=mid)return ask_in_tree(now<<1,x,y);
    else if (x>mid)return ask_in_tree(now<<1|1,x,y);
    else return merge(ask_in_tree(now<<1,x,mid),ask_in_tree(now<<1|1,mid+1,y));
}
inline segtree ask(int from,int to,bool flag)
{
    int l,r;
    segtree s;s.l=s.r=0;
    while (belong[from]!=belong[to])
    {
        l=place[belong[from]];
        r=place[from];
        s=merge(ask_in_tree(1,l,r),s);
        from=fa[belong[from]][0];
    }
    l=place[to];
    r=place[from];
    if (flag)
    {
    	if (place[to]+1<=place[from])s=merge(ask_in_tree(1,l+1,r),s);
    }else s=merge(ask_in_tree(1,l,r),s);
    return s;
}
inline void cal()
{
    int a=read(),b=read(),lca=LCA(a,b);
    if (!mrkl[a]&&!mrkr[a]){printf("0\n");return;}
    segtree q1=ask(a,lca,1);
    segtree q2=ask(b,lca,0);
	swap(q1.a_to_b,q1.b_to_a);
    swap(q1.mxl1,q1.mxr1);
    swap(q1.mxl2,q1.mxr2);
    q1=merge(q1,q2);
    int ans=max(q1.a_to_a,q1.a_to_b,q1.b_to_a,q1.b_to_b,q1.mxl1,q1.mxl2);
    if (ans==-1)ans=0;
    printf("%d\n",ans);
}
inline void change_in_tree(int now,int x,bool m1,bool m2)
{
    int l=tree[now].l,r=tree[now].r;
    if (l==r)
    {
        tree[now].a_to_a=tree[now].a_to_b=tree[now].b_to_a=tree[now].b_to_b=-1;
        tree[now].mxl1=tree[now].mxl2=tree[now].mxr1=tree[now].mxr2=-1;
        if (m1)tree[now].a_to_a=1,tree[now].mxl1=tree[now].mxr1=1;
        if (m2)tree[now].b_to_b=1,tree[now].mxl2=tree[now].mxr2=1;
        if (m1&&m2)
		{
			tree[now].a_to_b=tree[now].b_to_a=2;
			tree[now].mxl1=tree[now].mxl2=tree[now].mxr1=tree[now].mxr2=2;
		}
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid)change_in_tree(now<<1,x,m1,m2);
    else change_in_tree(now<<1|1,x,m1,m2);
    tree[now]=merge(tree[now<<1],tree[now<<1|1]);
}
inline void wrk()
{
    int a=read();
    bool m1=0,m2=0;
    char ch=getchar();while (ch!=‘.‘&&ch!=‘#‘)ch=getchar();
    if (ch==‘.‘)mrkl[a]=m1=1;
    ch=getchar();while (ch!=‘.‘&&ch!=‘#‘)ch=getchar();
    if (ch==‘.‘)mrkr[a]=m2=1;
    change_in_tree(1,place[a],m1,m2);
}
int main()
{
    n=read();m=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        insert(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        char ch=getchar();while (ch!=‘#‘&&ch!=‘.‘)ch=getchar();
        if (ch==‘.‘)mrkl[i]=1;
        ch=getchar();while (ch!=‘#‘&&ch!=‘.‘)ch=getchar();
        if (ch==‘.‘)mrkr[i]=1;
    }
    dfs1(1,0);
    dfs2(1,1);
    buildtree(1,1,n);
    for(int i=1;i<=m;i++)
    {
        char opr=getchar();
        while (opr!=‘Q‘&&opr!=‘C‘)opr=getchar();
        if (opr==‘Q‘)cal();
        if (opr==‘C‘)wrk();
    }
    return 0;
}

  

时间: 2024-10-12 21:36:34

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

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

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

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]道馆之战 线段树+树链剖分

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

2325: [ZJOI2011]道馆之战

2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 813  Solved: 309[Submit][Status] Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开. 三个冰地分别如下: 当走出第三个冰地之后,就可以与馆主进行道馆战了. 馆

[ZJOI2011]道馆之战

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

大神刷题表

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条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由