【bzoj2325】【ZJOI2011】【道馆之战】【树链剖分】

2024-02-20 15:38

本文主要是介绍【bzoj2325】【ZJOI2011】【道馆之战】【树链剖分】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

口袋妖怪(又名神奇宝贝或宠物小精灵)//绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次。当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开。

三个冰地分别如下:

当走出第三个冰地之后,就可以与馆主进行道馆战了。

馆主发现这个难度太小,导致经常有挑战者能通过,为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一条路径相连,即这n个房间构成一个树状结构。

每个房间分成了AB两个区域,每一区域都是一个薄冰块或者障碍物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)或这个房间的另一区域。

现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。

自从馆主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

Input

第一行包含两个正整数nm

2行到第n行,每行包含两个正整数xy,表示一条连接房间x和房间y的边。房间编号为1n

接下来n行,每行包含两个字符。第n + k行表示房间k的两个区域,第一个字符为A区域,第二个字符为B区域。其中“.(ASCII码为46)表示是薄冰块,“#(ASCII码为35)表示是障碍物。

最后的m行,每行一个操作:

u s:将房间u里的两个区域修改为s

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


 80 000

题解:浙江省出这题竟然没有区间修改。
          用a,b,c,d分别表示从左上到右上,从左上到右下,从左下到右上,从左下到右下最多经过的冰块数.
          用l1,l2,r1,r2分别表示从左上,左下,右上,右下出发最多经过的冰块数.
          合并什么的自行yy吧,也不是很复杂。
          注意询问的时候要把x-lca(x,y)-y中x-lca(x,y)这条链反过来再合并。
 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 30010
#define INF 100000000
using namespace std;
int point[N],next[N*2],sz,pos[N],n,m,x,y,cnt,deep[N],fa[N][20],bl[N],size[N];
struct use{int st,en;}e[N*2]; 
char ch[N][2],opt[2];
struct seg{int a,b,c,d,l1,l2,r1,r2;}t[N*4];
void add(int x,int y){next[++cnt]=point[x];point[x]=cnt;e[cnt].en=y;}
int lca(int x,int y){if (deep[x]<deep[y]) swap(x,y); int t=deep[x]-deep[y];for (int i=0;i<=18;i++) if (t&(1<<i)) x=fa[x][i];for (int i=18;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];if (x==y) return x;else return fa[x][0];
}
seg updata(seg x,seg y){seg tt;tt.a=max(x.a+y.a,x.b+y.c);if (tt.a<0) tt.a=-INF;tt.b=max(x.a+y.b,x.b+y.d);if (tt.b<0) tt.b=-INF;tt.c=max(x.c+y.a,x.d+y.c);if (tt.c<0) tt.c=-INF;tt.d=max(x.d+y.d,x.c+y.b);if (tt.d<0) tt.d=-INF;tt.l1=max(x.a+y.l1,x.b+y.l2);tt.l1=max(tt.l1,x.l1);if (tt.l1<0) tt.l1=-INF;tt.l2=max(x.c+y.l1,x.d+y.l2);tt.l2=max(tt.l2,x.l2);if (tt.l2<0) tt.l2=-INF;tt.r1=max(y.a+x.r1,y.c+x.r2);tt.r1=max(tt.r1,y.r1);if (tt.r1<0) tt.r1=-INF;tt.r2=max(y.b+x.r1,y.d+x.r2);tt.r2=max(tt.r2,y.r2);if (tt.r2<0) tt.r2=-INF;	 return tt;
}
void change(int k,int l,int r,int x,char ch[2]){int mid=(l+r)>>1;if (l==r){t[k].a=t[k].b=t[k].c=t[k].d=-INF;t[k].l1=t[k].l2=t[k].r1=t[k].r2=-INF;if (ch[0]=='.') t[k].a=t[k].l1=t[k].r1=1;if (ch[1]=='.') t[k].d=t[k].l2=t[k].r2=1;if (ch[0]=='.'&&ch[1]=='.') t[k].b=t[k].c=t[k].l1=t[k].l2=t[k].r1=t[k].r2=2; return ;}if (x<=mid) change(k<<1,l,mid,x,ch);else change(k<<1|1,mid+1,r,x,ch);	t[k]=updata(t[k<<1],t[k<<1|1]);
} 
seg query(int k,int l,int r,int ll,int rr){int mid=(l+r)>>1;if(l==ll&&r==rr){return t[k];}if(mid>=rr)return query(k<<1,l,mid,ll,rr);else if(mid<ll) return query(k<<1|1,mid+1,r,ll,rr);else return updata(query(k<<1,l,mid,ll,mid),query(k<<1|1,mid+1,r,mid+1,rr));
}
seg cal(int x,int y,bool ff){seg ans;ans.l1=ans.l2=ans.r1=ans.r2=0;ans.a=ans.b=ans.c=ans.d=0;while(bl[x]!=bl[y]){ans=updata(query(1,1,n,pos[bl[x]],pos[x]),ans);x=fa[bl[x]][0];}if(ff==1){if(pos[y]+1<=pos[x])ans=updata(query(1,1,n,pos[y]+1,pos[x]),ans);}else ans=updata(query(1,1,n,pos[y],pos[x]),ans);return ans;
}
void solve(int x,int y){if(ch[x][0]=='#'&&ch[x][1]=='#'){printf("0\n");return;}int f=lca(x,y);seg a=cal(x,f,1),b=cal(y,f,0);swap(a.b,a.c);swap(a.l1,a.r1);swap(a.l2,a.r2);seg ans=updata(a,b);printf("%d\n",max(ans.l1,ans.l2));
}
void dfs(int x){size[x]=1;for (int i=1;(1<<i)<=deep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1];for (int i=point[x];i;i=next[i])if (e[i].en!=fa[x][0]){deep[e[i].en]=deep[x]+1;fa[e[i].en][0]=x;dfs(e[i].en);size[x]+=size[e[i].en];}
} 
void dfs2(int x,int c){pos[x]=++sz;bl[x]=c;int k(0);change(1,1,n,pos[x],ch[x]);for (int i=point[x];i;i=next[i])if (e[i].en!=fa[x][0]&&size[e[i].en]>size[k]) k=e[i].en;if (!k) return;dfs2(k,c);for (int i=point[x];i;i=next[i])if(e[i].en!=k&&e[i].en!=fa[x][0]) dfs2(e[i].en,e[i].en); 
}
int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n-1;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}	for(int i=1;i<=n;i++)scanf("%s",ch[i]);dfs(1);dfs2(1,1);for (int i=1;i<=m;i++){scanf("%s",opt);if (opt[0]=='Q'){scanf("%d%d",&x,&y);solve(x,y);}else{scanf("%d",&x);scanf("%s",ch[x]);change(1,1,n,pos[x],ch[x]);}} 
} 


这篇关于【bzoj2325】【ZJOI2011】【道馆之战】【树链剖分】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/728688

相关文章

树链剖分 + 后缀数组 - E. Misha and LCP on Tree

E. Misha and LCP on Tree  Problem's Link   Mean:  给出一棵树,每个结点上有一个字母。每个询问给出两个路径,问这两个路径的串的最长公共前缀。 analyse: 做法:树链剖分+后缀数组. 记录每条链的串,正反都需要标记,组成一个长串. 然后记录每条链对应的串在大串中的位置,对大串求后缀数组,最后询问就是在一些链

【HDU】5029 Relief grain 树链剖分+离线标记法

传送门:【HDU】5029 Relief grain 题目分析:这题的方法太美妙了! 首先看到这是一颗树,那么很容易想到树链剖分。然后想到可以将查询排个序,然后每一种查询执行完以后更新每个点的最优值。但是这样进行的复杂度太高!尤其是当z给的没有一样的时候尤其如此。 那么我们是否可以找到更加高效的算法? 答案是肯定的! 先简化一下问题,如果这些操作是在线段上进行的,我们怎么求解?

【HDU】5221 Occupation【树链剖分】

传送门:【HDU】5221 Occupation 题目分析: 最直接的想法,用一棵树链剖分维护路径,一棵dfs序线段树维护子树。因为每次最多修改一个点,所以修改的时候我们暴力修改每个点就可以了。 my  code: my~~code: #pragma comment(linker, "/STACK:102400000,102400000")#include <stdio.h>#in

【HDU】5436 Transmigration tree【树链剖分+dp+rmq】

题目链接:【HDU】5436 Transmigration tree #pragma comment(linker, "/STACK:16777216")#include <stdio.h>#include <string.h>#include <vector>#include <algorithm>using namespace std ;typedef long long LL ;

【HDU】5566 Clarke and room【树链剖分+AC自动机】

题目链接:Clarke and room #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define ls ( o << 1 )#define lson ls , l , m#define rs ( o << 1 | 1 )#define rson rs , m + 1 , r#define rt

Open3D mesh 模型精细化处理--中点剖分

目录 一、概述 1.1原理 1.2实现步骤 二、代码实现 2.1关键函数 输入参数 输出参数 三、实现效果 3.1原始mesh 3.2精细化mesh Open3D点云算法汇总及实战案例汇总的目录地址: Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客 一、概述         在三维模型处理过程中,精细化处理(subdivision)是一个

《血族》全民模式火热开启 南北之战一触即发

“岁至端午夏日长,花丛锦绣醉芬芳。大江南北共一色,不时飘来粽清香。”今天是五月初五,即中国传统节日——端午节。在此,小编祝各位大盆友小盆友们,端午节快乐~     端午有三事:品粽香、赛龙舟、戴彩绳。然而,如今的端午节又新增一项不可避免的节目:南北咸甜粽子之争。自古以来,南方人与北方人在口味上总是有着一定的差异,如咸甜豆腐脑。端午的到来,又引发了对于咸甜粽子口味的讨论,那么,亲们会

Dominant Indices【模板】长链剖分

~~~~~      Dominant Indices ~~~~~      总题单链接 对比重链剖分和长链剖分 ~~~~~      什么是重链剖分:根据子树的大小将树拆成多条互不相交的链。 ~~~~~      什么是长链剖分:根据字数的深度将树拆成多条互不相交的链。 ~~~~~      重链剖分中的重儿子:子树大小最大的儿子。 ~~~~~      长链剖分中的重儿子:

hdu5052 Yaoge’s maximum profit 树链剖分

一棵树上,从u走到v,在某点买入,咋之后的某点卖出,求最大利润。 维护正着走和反着走的最大利润。 #include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#include<vector>#include<set>#include<map>#include<que

poj3237--Tree(树链剖分+线段树)

题目链接:poj--3237 题意很简单,给出n个节点的一棵树,有三种操作: 1、C修改第i条边的值为v 2、N改变节点a到b内边的权值的符号(取反) 3、Q询问节点a到b内权值的最大值 首先树链剖分,将边整合到线段树上,线段树数组cl,因为存在取反操作,所以最大值可能是由最小值取反得到,所以记录最大和最小值,cl[i][0]记录第i段的最大值,cl[i][1]记录最小值,lazy做标记