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

题目描述

口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中
的每一个冰块都只能经过一次。当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开。三个冰
地分别如下:
当走出第三个冰地之后,就可以与馆主进行道馆战了。馆主发现这个难度太小,导致经常有挑战者能通过,为了加
大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一
条路径相连,即这n个房间构成一个树状结构。每个房间分成了A和B两个区域,每一区域都是一个薄冰块或者障碍
物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)
或这个房间的另一区域。现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去
。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过
的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。自从馆
主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于
每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

输入

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

题目大意:给一棵树,树上每个点分为AB两个区域,每个区域可能是空地或障碍物,每次可以从一个点的一个区域走到相邻点的相同区域或走到这个点的另一个区域,每次能走的前提是走到的区域是空地,一个点的一个区域只能走一次(也就是说从一个区域走出去就不能走回来了)。有两种操作:1、修改一个点的两个区域。2、查询从u的任意空地区域走到v最多能走多少步,可以不到达v,如果u无空地输出0。

显然是用树链剖分+线段树,线段树维护连通性(最长路)。

维护连通性的方法和BZOJ1018类似(建议先做一下bzoj1018再做这道题)。

线段树的每个点维护8个信息,分别是从左上到右上(luru)、从左上到右下(lurd)、从左下到右上(ldru)、从左下到右下(ldrd)的最长路,如果不连通就是0。
以及区间从左上(lumx)、左下(ldmx)、右上(rumx)、右下(rdmx)开始向另一边走的最长路。
线段树回溯时O(1)合并子节点区间信息。
修改时直接修改对应点在线段树中沿途更新信息。
查询时树链剖分往上跳,每次跳时将当次查询区间合并。
因为是从u走到v,所以u和v有一边到lca的区间是反的,需要把这一边跳完合并后的区间翻转一下再与另一边的区间合并。
翻转时直接将区间的左端右端信息交换。
代码有点长,见谅。
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct miku
{
    int luru;
    int ldrd;
    int lurd;
    int ldru;
    int lumx;
    int ldmx;
    int rumx;
    int rdmx;
    int l,r;
}t[400010];
int n,m;
int x,y;
int num;
int tot;
char c[4];
char ch[4];
int f[50010];
int d[50010];
int s[50010];
int q[50010];
int to[100010];
int son[50010];
int top[50010];
int size[50010];
int head[50010];
int a[50010][4];
int next[100010];
void add(int x,int y)
{
    tot++;
    next[tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}
void dfs(int x)
{
    size[x]=1;
    d[x]=d[f[x]]+1;
    for(int i=head[x];i;i=next[i])
    {
        if(to[i]!=f[x])
        {
            f[to[i]]=x;
            dfs(to[i]);
            size[x]+=size[to[i]];
            if(size[to[i]]>size[son[x]])
            {
                son[x]=to[i];
            }
        }
    }
}
void dfs2(int x,int tp)
{
    top[x]=tp;
    s[x]=++num;
    q[num]=x;
    if(son[x])
    {
        dfs2(son[x],tp);
    }
    for(int i=head[x];i;i=next[i])
    {
        if(to[i]!=f[x]&&to[i]!=son[x])
        {
            dfs2(to[i],to[i]);
        }
    }
}
void merge(miku &z,miku x,miku y)
{
    z.l=x.l;
    z.r=y.r;
    z.luru=0;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.luru&&y.luru)
    {
        z.luru=max(x.luru+y.luru,z.luru);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.lurd&&y.ldru)
    {
        z.luru=max(x.lurd+y.ldru,z.luru);
    }
    z.lurd=0;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.luru&&y.lurd)
    {
        z.lurd=max(x.luru+y.lurd,z.lurd);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.lurd&&y.ldrd)
    {
        z.lurd=max(x.lurd+y.ldrd,z.lurd);
    }
    z.ldru=0;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.ldru&&y.luru)
    {
        z.ldru=max(x.ldru+y.luru,z.ldru);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.ldrd&&y.ldru)
    {
        z.ldru=max(x.ldrd+y.ldru,z.ldru);
    }
    z.ldrd=0;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.ldru&&y.lurd)
    {
        z.ldrd=max(x.ldru+y.lurd,z.ldrd);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.ldrd&&y.ldrd)
    {
        z.ldrd=max(x.ldrd+y.ldrd,z.ldrd);
    }
    z.lumx=x.lumx;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.luru)
    {
        z.lumx=max(x.luru+y.lumx,z.lumx);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.lurd)
    {
        z.lumx=max(x.lurd+y.ldmx,z.lumx);
    }
    z.ldmx=x.ldmx;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&x.ldru)
    {
        z.ldmx=max(x.ldru+y.lumx,z.ldmx);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&x.ldrd)
    {
        z.ldmx=max(x.ldrd+y.ldmx,z.ldmx);
    }
    z.rumx=y.rumx;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&y.luru)
    {
        z.rumx=max(y.luru+x.rumx,z.rumx);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&y.ldru)
    {
        z.rumx=max(y.ldru+x.rdmx,z.rumx);
    }
    z.rdmx=y.rdmx;
    if(a[q[x.r]][1]&&a[q[y.l]][1]&&y.lurd)
    {
        z.rdmx=max(y.lurd+x.rumx,z.rdmx);
    }
    if(a[q[x.r]][2]&&a[q[y.l]][2]&&y.ldrd)
    {
        z.rdmx=max(y.ldrd+x.rdmx,z.rdmx);
    }
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        t[rt].l=l;
        t[rt].r=r;
        if(a[q[l]][1]==1&&a[q[l]][2]==1)
        {
            t[rt].luru=t[rt].ldrd=1;
            t[rt].lurd=t[rt].ldru=2;
            t[rt].lumx=t[rt].ldmx=t[rt].rumx=t[rt].rdmx=2;
        }
        else if(a[q[l]][1]==1&&a[q[l]][2]==0)
        {
            t[rt].luru=t[rt].lumx=t[rt].rumx=1;
        }
        else if(a[q[l]][1]==0&&a[q[l]][2]==1)
        {
            t[rt].ldrd=t[rt].ldmx=t[rt].rdmx=1;
        }
        return ;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    merge(t[rt],t[rt<<1],t[rt<<1|1]);
}
void clear(miku &x)
{
    x.luru=x.lurd=x.ldru=x.ldrd=0;
    x.lumx=x.ldmx=x.rumx=x.rdmx=0;
}
void change(int rt,int l,int r,int k)
{
    if(l==r)
    {
        clear(t[rt]);
        if(a[q[l]][1]==1&&a[q[l]][2]==1)
        {
            t[rt].luru=t[rt].ldrd=1;
            t[rt].lurd=t[rt].ldru=2;
            t[rt].lumx=t[rt].ldmx=t[rt].rumx=t[rt].rdmx=2;
        }
        else if(a[q[l]][1]==1&&a[q[l]][2]==0)
        {
            t[rt].luru=t[rt].lumx=t[rt].rumx=1;
        }
        else if(a[q[l]][1]==0&&a[q[l]][2]==1)
        {
            t[rt].ldrd=t[rt].ldmx=t[rt].rdmx=1;
        }
        return ;
    }
    int mid=(l+r)>>1;
    if(k<=mid)
    {
        change(rt<<1,l,mid,k);
    }
    else
    {
        change(rt<<1|1,mid+1,r,k);
    }
    merge(t[rt],t[rt<<1],t[rt<<1|1]);
}
miku query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return t[rt];
    }
    int mid=(l+r)>>1;
    if(R<=mid)
    {
        return query(rt<<1,l,mid,L,R);
    }
    if(L>mid)
    {
        return query(rt<<1|1,mid+1,r,L,R);
    }
    miku res;
    merge(res,query(rt<<1,l,mid,L,R),query(rt<<1|1,mid+1,r,L,R));
    return res; 
}
void rotate(miku &x)
{
    swap(x.lurd,x.ldru);
    swap(x.lumx,x.rumx);
    swap(x.ldmx,x.rdmx);
    swap(x.l,x.r);
}
int lca(int x,int y)
{
    miku res;
    miku ans;
    clear(ans);
    clear(res);
    int tx=0;
    int ty=0;
    while(top[x]!=top[y])
    {
        if(d[top[x]]>d[top[y]])
        {
            if(tx==0)
            {
                res=query(1,1,n,s[top[x]],s[x]);
                tx=1;
            }
            else
            {
                merge(res,query(1,1,n,s[top[x]],s[x]),res);
            }
            x=f[top[x]];
        }
        else
        {
            if(ty==0)
            {
                ans=query(1,1,n,s[top[y]],s[y]);
                ty=1;
            }
            else
            {
                merge(ans,query(1,1,n,s[top[y]],s[y]),ans);
            }
            y=f[top[y]];
        }
    }
    if(d[x]<d[y])
    {
        rotate(res);
        if(tx==0)
        {
            res=query(1,1,n,s[x],s[y]);
        }
        else
        {
            merge(res,res,query(1,1,n,s[x],s[y]));
        }
        if(ty!=0)
        {
            merge(res,res,ans);
        }
        return max(res.lumx,res.ldmx);
    }
    else
    {
        if(ty!=0)
        {
            rotate(ans);
        }
        if(tx==0)
        {
            res=query(1,1,n,s[y],s[x]);
        }
        else
        {
            merge(res,query(1,1,n,s[y],s[x]),res);
        }
        if(ty!=0)
        {
            merge(res,ans,res);
        }
        return max(res.rumx,res.rdmx);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ch);
        if(ch[0]=='.')
        {
            a[i][1]=1;
        }
        else
        {
            a[i][1]=0;
        }
        if(ch[1]=='.')
        {
            a[i][2]=1;
        }
        else
        {
            a[i][2]=0;
        }
    }
    dfs(1);
    dfs2(1,1);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",c);
        if(c[0]=='Q')
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",lca(x,y));
        }
        else
        {
            scanf("%d",&x);
            scanf("%s",ch);
            if(ch[0]=='.')
            {
                a[x][1]=1;
            }
            else
            {
                a[x][1]=0;
            }
            if(ch[1]=='.')
            {
                a[x][2]=1;
            }
            else
            {
                a[x][2]=0;
            }
            change(1,1,n,s[x]);
        }
    }
}
posted @ 2018-09-26 23:35  The_Virtuoso  阅读(253)  评论(0编辑  收藏  举报