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。
N≤ 30 000
M ≤ 80 000
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
分析:
好好的读过题后,题目可以总结为:一个树形结构,对于树上的路径查询或修改
可以想到用树链剖分完成
对于每一个结点的两部分,我们黑白染色
剖完之后,线段树的每个结点中代表的是树上的一条链
那么我们在这条链上维护八个值:
dis[1][1]:左端黑色<—>右端黑色
dis[1][0]:左端黑色<—>右端白色
dis[0][1]:左端白色<—>右端黑色
dis[0][0]:左端白色<—>右端白色
rs[1]:右端黑色向左能够延伸的最长距离
rs[0]:右端白色向左能够延伸的最长距离
ls[1]:左端黑色向右能够延伸的最长距离
ls[0]:左端白色向右能够延伸的最长距离
随意维护上述信息
我们在询问一条链的时候,分成了两部分:x—>lca,lca—>y
在用树链剖分进行询问的时候,分别维护两条链
最后在把两条链合并,但是在合并的时候,需要把一条链翻转
才能保证答案正确
翻转链:
swap(dis[0][1],dis[1][0])
s
w
a
p
(
d
i
s
[
0
]
[
1
]
,
d
i
s
[
1
]
[
0
]
)
swap(ls[0],rs[0])
s
w
a
p
(
l
s
[
0
]
,
r
s
[
0
]
)
swap(ls[1],rs[1])
s
w
a
p
(
l
s
[
1
]
,
r
s
[
1
]
)
tip
写着写着就想到了这道题
不好写。。。orz
ask的时候不要乱swap
使用新的线段树结点时不要忘了初始化
查了半天错,发现是update写残了。。。
不知道为什么最后一步的update怎么也传不出正确答案了。。。怎么改不知道啊
于是就把update由函数变成重载运算符
但是这样还是不行,于是又重载了减号(翻转)
这样才过了样例,但是WA了
只能看前辈的代码了。。。
不知道为什么今天写什么都A不掉。。。—>AC代码
//A不了C代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int INF=1<<30;
const int N=30010;
int n,m,st[N],tot=0,mp[N][2];
struct node{
int y,nxt;
};
node way[N<<1];
struct Tree{
int dis[2][2],rs[2],ls[2];
Tree()
{
memset(dis,0,sizeof(dis));
memset(rs,0,sizeof(rs));
memset(ls,0,sizeof(ls));
dis[0][1]=dis[1][0]=-INF;
}
Tree(int x)
{
if (mp[x][0]&&mp[x][1]) {
ls[0]=ls[1]=rs[0]=rs[1]=dis[0][1]=dis[1][0]=2;
dis[0][0]=dis[1][1]=1;
} else if (mp[x][0]) {
ls[0]=rs[0]=dis[0][0]=1;
ls[1]=rs[1]=0;
dis[0][1]=dis[1][0]=dis[1][1]=-INF;
} else if (mp[x][1]) {
ls[1]=rs[1]=dis[1][1]=1;
ls[0]=rs[0]=0;
dis[0][0]=dis[0][1]=dis[1][0]=-INF;
} else {
ls[0]=ls[1]=rs[0]=rs[1]=0;
dis[0][1]=dis[1][0]=dis[1][1]=dis[0][0]=-INF;
}
}
friend Tree operator +(const Tree &l,const Tree &r)
{
Tree ans;
ans.ls[0]=max(l.ls[0] , max(l.dis[0][1]+r.ls[1] , l.dis[0][0]+r.ls[0]));
ans.ls[1]=max(l.ls[1] , max(l.dis[1][1]+r.ls[1] , l.dis[1][0]+r.ls[0]));
ans.rs[0]=max(r.rs[0] , max(r.dis[1][0]+l.rs[1] , r.dis[0][0]+l.rs[0]));
ans.rs[1]=max(r.rs[1] , max(r.dis[0][1]+l.rs[0] , r.dis[1][1]+l.rs[1]));
ans.dis[0][0]=max(-INF , max(l.dis[0][0]+r.dis[0][0] , l.dis[0][1]+r.dis[1][0]));
ans.dis[0][1]=max(-INF , max(l.dis[0][0]+r.dis[0][1] , l.dis[0][1]+r.dis[1][1]));
ans.dis[1][0]=max(-INF , max(l.dis[1][0]+r.dis[0][0] , l.dis[1][1]+r.dis[1][0]));
ans.dis[1][1]=max(-INF , max(l.dis[1][0]+r.dis[0][1] , l.dis[1][1]+r.dis[1][1]));
return ans;
}
Tree operator -() const
{
Tree ans;
ans.ls[0]=rs[0] , ans.ls[1]=rs[1];
ans.rs[0]=ls[0] , ans.rs[1]=ls[1];
ans.dis[0][0]=dis[0][0] , ans.dis[0][1]=dis[1][0];
ans.dis[1][0]=dis[0][1] , ans.dis[1][1]=dis[1][1];
return ans;
}
};
Tree t[N<<2];
int num[N],shu[N],size[N],son[N],top[N],deep[N],pre[N],clo=0;
void add(int x,int y)
{
tot++;
way[tot].y=y; way[tot].nxt=st[x]; st[x]=tot;
tot++;
way[tot].y=x; way[tot].nxt=st[y]; st[y]=tot;
}
void dfs_1(int now,int fa,int dep)
{
deep[now]=dep;
pre[now]=fa;
size[now]=1;
int maxx=0;
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa)
{
dfs_1(way[i].y,now,dep+1);
size[now]+=size[way[i].y];
if (size[way[i].y]>maxx)
maxx=size[way[i].y],son[now]=way[i].y;
}
}
void dfs_2(int now,int fa)
{
if (son[fa]!=now) top[now]=now;
else top[now]=top[fa];
num[now]=++clo; shu[num[now]]=now;
if (son[now])
{
dfs_2(son[now],now);
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa&&way[i].y!=son[now])
dfs_2(way[i].y,now);
}
}
void build(int bh,int l,int r)
{
if (l==r)
{
t[bh]=Tree(shu[l]);
return;
}
int mid=(l+r)>>1;
build(bh<<1,l,mid);
build(bh<<1|1,mid+1,r);
t[bh]=t[bh<<1]+t[bh<<1|1];
}
void change(int bh,int l,int r,int x)
{
if (l==r)
{
t[bh]=Tree(shu[l]);
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(bh<<1,l,mid,x);
else change(bh<<1|1,mid+1,r,x);
t[bh]=t[bh<<1]+t[bh<<1|1];
}
Tree asksum(int bh,int l,int r,int L,int R)
{
if (l>=L&&r<=R) return t[bh];
int mid=(l+r)>>1;
if (R<=mid) return asksum(bh<<1,l,mid,L,R);
else if (L>mid) return asksum(bh<<1|1,mid+1,r,L,R);
return asksum(bh<<1,l,mid,L,R)+asksum(bh<<1|1,mid+1,r,L,R);
}
int ask(int x,int y)
{
Tree A,B,C;
int f1=top[x];
int f2=top[y];
while (f1!=f2)
{
if (deep[f1]>deep[f2]) {
A=asksum(1,1,n,num[f1],num[x])+A;
x=pre[f1];
f1=top[x];
}
else {
B=asksum(1,1,n,num[f2],num[y])+B;
y=pre[f2];
f2=top[y];
}
}
if (deep[x]>deep[y])
A=asksum(1,1,n,num[y],num[x])+A;
else B=asksum(1,1,n,num[x],num[y])+B;
A=-A+B;
return max(A.ls[0],A.ls[1]);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
char s[5];
for (int i=1;i<=n;i++)
{
scanf("%s",s);
for (int j=0;j<=1;j++)
if (s[j]=='.') mp[i][j]=1;
else mp[i][j]=0;
}
dfs_1(1,0,1);
dfs_2(1,0);
build(1,1,n);
int x,y;
for (int i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='C')
{
scanf("%d",&x); scanf("%s",s);
for (int j=0;j<=1;j++)
if (s[j]=='.') mp[x][j]=1;
else mp[x][j]=0;
change(1,1,n,num[x]); //num[x]
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
}
}
return 0;
}