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
题目描述太蛋疼了……
总结一下就是一棵树上,每个点有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