【题解】Luogu P4679 [ZJOI2011]道馆之战
原题传送门
码农题树剖好题,口袋妖怪是个好玩的游戏
这道题要用树链剖分,我博客里有对树链剖分的详细介绍
下文左右就代表树的节点按dfs序后的左右,上、下分别表示每个节点的A、B区域
考虑在链上的情况,在当前考虑的区间中,令dis[0][0]表示从左上走到右上的最长路,dis[0][1]表示从左上到右下,dis[1][0],dis[1][1]以此类推. 令maxx[0][0]表示从左上出发能走的最大距离,maxx[0][1]表示左下的,maxx[1][0]表示右上,maxx[1][1]表示右下.它们的合并比较简单.令当前区间为c,左半区间为a,右半区间为b,那么:
c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));
在树上怎么办呢?每次询问的是两个点之间的路径,很显然,要用线段树+树链剖分. 如果询问的两个点分别是x,y,令lans表示x向上跳得到的答案,rans表示y向上跳得到的答案,最后要将lans取反再与rans合并,因为当两个点最后跳到一起时,它们的左端点对应左端点,右端点对应右端点,而我们要求左端点对应右端点,右端点对应左端点,所以要取反(这个珂以画个图理解一下子)
#include <bits/stdc++.h>
#define N 50005
#define inf (1<<30)
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline void Swap(register int &a,register int &b)
{
a^=b^=a^=b;
}
inline int Max(register int x,register int y)
{
return x>y?x:y;
}
struct edge{
int to,next;
}eg[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
eg[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int n,m;
int size[N],dep[N],fa[N],son[N];
int tot=0,dl[N],id[N],top[N];
int a[N][2];
inline void dfs1(register int x,register int faa)
{
fa[x]=faa;
size[x]=1;
dep[x]=dep[faa]+1;
for(register int i=head[x];i;i=eg[i].next)
{
int v=eg[i].to;
if(v==faa)
continue;
dfs1(v,x);
size[x]+=size[v];
if(size[v]>size[son[x]])
son[x]=v;
}
}
inline void dfs2(register int x,register int t)
{
dl[x]=++tot;
id[tot]=x;
top[x]=t;
if(son[x])
dfs2(son[x],t);
for(register int i=head[x];i;i=eg[i].next)
{
int v=eg[i].to;
if(v==fa[x]||v==son[x])
continue;
dfs2(v,v);
}
}
struct node{
int dis[2][2],maxx[2][2];
inline void clear()
{
memset(dis,0,sizeof(dis));
memset(maxx,0,sizeof(maxx));
}
inline bool emptyy()
{
if(!dis[0][0]&&!dis[0][1]&&!dis[1][0]&&!dis[1][1]&&!maxx[0][0]&&!maxx[0][1]&&!maxx[1][0]&&!maxx[1][1])
return true;
return false;
}
}e[N<<2];
inline node pushup(register node a,register node b)
{
node c;
if(a.emptyy())
c=b;
else if(b.emptyy())
c=a;
else
{
c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));
}
return c;
}
inline void build(register int x,register int l,register int r)
{
if(l==r)
{
int p=a[id[l]][0],q=a[id[l]][1];
if(p==1&&q==1)
{
e[x].dis[0][0]=e[x].dis[1][1]=1;
e[x].dis[0][1]=e[x].dis[1][0]=2;
e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
}
else if(p==1)
{
e[x].dis[0][0]=1;
e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
e[x].maxx[0][0]=e[x].maxx[1][0]=1;
e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
}
else if(q==1)
{
e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
e[x].dis[1][1]=1;
e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
e[x].maxx[0][1]=e[x].maxx[1][1]=1;
}
else
{
for(register int i=0;i<=1;++i)
for(register int j=0;j<=1;++j)
e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
}
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline void update(register int x,register int l,register int r,register int v,register int p,register int q)
{
if(l==r)
{
if(p==1&&q==1)
{
e[x].dis[0][0]=e[x].dis[1][1]=1;
e[x].dis[0][1]=e[x].dis[1][0]=2;
e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
}
else if(p==1)
{
e[x].dis[0][0]=1;
e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
e[x].maxx[0][0]=e[x].maxx[1][0]=1;
e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
}
else if(q==1)
{
e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
e[x].dis[1][1]=1;
e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
e[x].maxx[0][1]=e[x].maxx[1][1]=1;
}
else
{
for(register int i=0;i<=1;++i)
for(register int j=0;j<=1;++j)
e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
}
return;
}
int mid=l+r>>1;
if(v<=mid)
update(x<<1,l,mid,v,p,q);
else
update(x<<1|1,mid+1,r,v,p,q);
e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline node rev(register node a)
{
Swap(a.maxx[0][0],a.maxx[1][0]);
Swap(a.maxx[0][1],a.maxx[1][1]);
Swap(a.dis[0][1],a.dis[1][0]);
return a;
}
inline node query(register int x,register int l,register int r,register int L,register int R)
{
if(l==L&&r==R)
return e[x];
int mid=l+r>>1;
if(R<=mid)
return query(x<<1,l,mid,L,R);
else if(L>mid)
return query(x<<1|1,mid+1,r,L,R);
else
return pushup(query(x<<1,l,mid,L,mid),query(x<<1|1,mid+1,r,mid+1,R));
}
inline int Query(register int x,register int y)
{
node lans,rans;
lans.clear();
rans.clear();
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
rans=pushup(query(1,1,n,dl[top[y]],dl[y]),rans);
y=fa[top[y]];
}
else
{
lans=pushup(query(1,1,n,dl[top[x]],dl[x]),lans);
x=fa[top[x]];
}
}
if(dep[x]>dep[y])
lans=pushup(query(1,1,n,dl[y],dl[x]),lans);
else
rans=pushup(query(1,1,n,dl[x],dl[y]),rans);
lans=pushup(rev(lans),rans);
int res=Max(lans.maxx[0][0],lans.maxx[0][1]);
return res<0?0:res;
}
int main()
{
n=read(),m=read();
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1,0);
dfs2(1,1);
for(register int i=1;i<=n;++i)
{
char ch[3];
scanf("%s",ch);
a[i][0]=(ch[0]=='.')?1:0;
a[i][1]=(ch[1]=='.')?1:0;
}
build(1,1,n);
while(m--)
{
char c=getchar();
while(c!='C'&&c!='Q')
c=getchar();
if(c=='C')
{
int u=read();
char s[3];
scanf("%s",s);
int p=(s[0]=='.')?1:0,q=(s[1]=='.')?1:0;
update(1,1,n,dl[u],p,q);
}
else
{
int u=read(),v=read();
write(Query(u,v)),puts("");
}
}
return 0;
}
【题解】Luogu P4679 [ZJOI2011]道馆之战的更多相关文章
- 【BZOJ2325】[ZJOI2011]道馆之战 线段树+树链剖分
[BZOJ2325][ZJOI2011]道馆之战 Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过 ...
- bzoj2325 [ZJOI2011]道馆之战
Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个 ...
- BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树
题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...
- [ZJOI2011]道馆之战
Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个 ...
- BZOJ2325 [ZJOI2011]道馆之战 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2325 题意概括 给你一棵N个点的树,树上的每个节点有A,B两块区域,且每种区域有两种状态:可以走的 ...
- 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并
题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...
- bzoj2325 [ZJOI2011]道馆之战 树链剖分+DP+类线段树最大字段和
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2325 题解 可以参考线段树动态维护最大子段和的做法. 对于线段树上每个节点 \(o\),维护 ...
- bzoj千题计划243:bzoj2325: [ZJOI2011]道馆之战
http://www.lydsy.com/JudgeOnline/problem.php?id=2325 设线段树节点区间为[l,r] 每个节点维护sum[0/1][0/1] 从l的A/B区域到r的 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
随机推荐
- Java - Selenium 环境配置
1. 安装Java JDK - 文件自己下 2. 配置环境变量-重要! 我的电脑-属性-高级-环境变量 添加 CLASSPATH 值 .;%JAVA_HOME%\lib;%JAVA_HOME%\li ...
- Python解决乱码问题
解决python乱码问题 字符串在python的内部采用unicode的编码方式,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode ...
- Amber learning note A8: Loop Dynamics of the HIV-1 Integrase Core Domain
1. Prepare Input File $ tleap >source leaprc.protein.ff14SB ----- Source: /home/wangq/Programs/am ...
- vue中打印显示++的问题解决方案(做成类似同步的操作就行了)
这个问题,困扰我很久很久 怎么实现的呢?首先进入页面就开始调取打印接口,打印接口的成功回调函数里面写 this.hasOut++(这是实时显示的数量)this.width=(this.hasOut/t ...
- cocos JS 定时器
cocos2d-js的定时器的创建跟使用: 情况一: var TestLayer = cc.Layer.extend({ sprite:null, ctor:function () { this.sc ...
- react native中使用native-echarts
第一步,下载依赖 npm install native-echarts --save 第二步,引入 import Echarts from 'native-echarts'; 第三步,使用 expor ...
- Css预处理器---Less(一)
一.简介: Less是一种动态样式语言,可以在样式中使用变量,继承,运算,函数 二.使用 (1)客户端使用 //引入您的.less样式文件,rel属性区别去css为stylesheet/less &l ...
- mysql 5.6 分区与不分区的区别
mysql> CREATE TABLE t1 ( id INT, date DATETIME DEFAULT CURRENT_TIMESTAMP) ENGINE=Innodb; Query OK ...
- SQLGetEnvAttr
SQLGetEnvAttr 函数定义: 用于得到当前环境的各项设置属性 SQLRETURN SQLGetEnvAttr( SQLHENV EnvironmentHandle, SQLINTEG ...
- 设置一个div网页滚动时,使其固定在头部,当页面滚动到距离头部300px时,隐藏该div,另一个div在底部,此时显示;当页面滚动到起始位置时,头部div出现,底部div隐藏
设置一个div网页滚动时,使其固定在头部,当页面滚动到距离头部300px时,隐藏该div,另一个div在底部,此时显示: 当页面滚动到起始位置时,头部div出现,底部div隐藏 前端代码: <! ...