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; }