【题解】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 ...
随机推荐
- vue2.0--请求数据
vue中用vue-reouse请求来的数据,会被封装一层,如下图res:
- CefGlue在WinXP下闪退的排查方法
用CefGlue开发的程序部署到多台机器上,运行正常.本以为没有问题了,下午突然接到客户电话说:运行程序时,闪一下就退出,没有任何错误提示!远程连接到客户机器上,看了下果然如此!cef没有记录任何日志 ...
- spring mvc配置datasource数据源的三种方式
2.使用org.apache.commons.dbcp.BasicDataSource 说明:这是一种推荐说明的数据源配置方式,它真正使用了连接池技术 <bean id="dataSo ...
- LA 2218 Triathlon(半平面交)
Triathlon [题目链接]Triathlon [题目类型]半平面交 &题解: 做了2道了,感觉好像套路,都是二分答案,判断半平面交是否为空. 还有刘汝佳的代码总是写const +& ...
- Koa中设置中文Cookie值
默认情况下, 如果 ctx.cookies.set('user', '杨过', { domain: 'xxxx', path: 'xxxx', maxAge: 24 * 60 * 60 * 1000, ...
- 003-SqlHelper.cs/Web.config
<?xml version="1.0" encoding="utf-8"?> <!-- 有关如何配置 ASP.NET 应用程序的详细信息,请访 ...
- Docker服务端和客户端
Docker是一个客户端-服务端(c/s)的架构程序
- vue--监听属性完成大小写字母间的转换
监听属性 watch侦听属性的作用是侦听某属性值的变化,从而做相应的操作,侦听属性是一个对象,它的键是要监听的对象或者变量,值一般是函数,当你侦听的元素发生变化时,需要执行的函数,这个函数有两个形参, ...
- Nodejs【单机】多进程模式集群
Nodejs[单机]多进程模式集群实例: 1.安装:npm install -s cluster 2.服务代码: var debug = require('debug'); var express = ...
- linux 中的screen出现cannot find terminfo entry 的错误
事情的起因: 本地使用urxvt terminal ,使用ssh方式远程登录服务器,远程在服务器端执行screen命令,然后就出现了cannot find terminfo entry的错误. 解决方 ...