原题传送门

码农题树剖好题,口袋妖怪是个好玩的游戏

这道题要用树链剖分,我博客里有对树链剖分的详细介绍

下文左右就代表树的节点按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]道馆之战的更多相关文章

  1. 【BZOJ2325】[ZJOI2011]道馆之战 线段树+树链剖分

    [BZOJ2325][ZJOI2011]道馆之战 Description 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中的每一个冰块都只能经过 ...

  2. bzoj2325 [ZJOI2011]道馆之战

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

  3. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

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

  4. [ZJOI2011]道馆之战

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

  5. BZOJ2325 [ZJOI2011]道馆之战 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2325 题意概括 给你一棵N个点的树,树上的每个节点有A,B两块区域,且每种区域有两种状态:可以走的 ...

  6. 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并

    题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...

  7. bzoj2325 [ZJOI2011]道馆之战 树链剖分+DP+类线段树最大字段和

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2325 题解 可以参考线段树动态维护最大子段和的做法. 对于线段树上每个节点 \(o\),维护 ...

  8. bzoj千题计划243:bzoj2325: [ZJOI2011]道馆之战

    http://www.lydsy.com/JudgeOnline/problem.php?id=2325 设线段树节点区间为[l,r] 每个节点维护sum[0/1][0/1]  从l的A/B区域到r的 ...

  9. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

随机推荐

  1. js神秘的电报密码---哈弗曼编码

    哈夫曼编码,根据每个单词在文本中出现的次数频率为权值,频率高的权值大.然后每次取两个频率最小的生成树,最后生成一颗大树.从根节点到该单词的路径,左边为0,右边为1, function HFM(){ v ...

  2. JAVA编程思想学习笔记5-chap13-15-斗之气5段

    1.String对象不可变,一旦发生字符变换或者变长度,一定是新建了一个String private final char value[]; 2.字符串+与+=:唯二操作符重载 "aaa&q ...

  3. cocos2d JS 设置字幕循环滚动(背景图滚动亦可)

    var dong = ccs.load("res/Login.json"); this.addChild(dong.node); this.cShamNotice = ccui.h ...

  4. Navicat Premium 安装与激活破解版简单操作 (原)

    首先下载navicate程序以及破解文件,这里一并存到了百度网盘直接下载即可 链接:https://pan.baidu.com/s/11ptFmsV1o3B5oB00zm2NdQ 密码:yw82 解压 ...

  5. 编写带有下列声明的例程:第一个例程是个驱动程序,它调用第二个例程并显示String str中的字符的所有排列。例如,str是"abc", 那么输出的串则是abc,acb,bac,bca,cab,cba,第二个例程使用递归。

    全排列在笔试面试中很热门,因为它难度适中,既可以考察递归实现,又能进一步考察非递归的实现,便于区分出考生的水平.所以在百度和迅雷的校园招聘以及程序员和软件设计师的考试中都考到了,因此本文对全排列作下总 ...

  6. AI案列 三条路

    在生成点生成带有颜色的小球,小球走对应颜色的路 先做好三个小球,做成预制体 对应颜色的小球,除了自身颜色,其他颜色不要选 新建脚本: using System.Collections; using S ...

  7. beego 初体验 - orm - 增删改查

    本文记录一下 beego orm 简单的增删改查,大牛请绕道. 首先,注册4个增删改查的路由: 其次,在 views 文件夹下增加对应的模板(页面): controller 类里写上增删改查的方法: ...

  8. 三级菜单(低端版VS高端版)

    >>>低端版 menu={'山西': {'太原': {'迎泽':['柳巷','五一广场','太原站'], '小店':['山西财经大学','山西大学','武宿机场'], '晋源':[' ...

  9. Mockito/PowerMockito Straige Issues

    http://blog.csdn.net/xiaoyaoyulinger/article/details/52415494 http://breezylee.iteye.com/blog/208843 ...

  10. VC2012+QT新建一个控制台程序

    1.新建一个项目,选择控制台程序 2.下一步.project setting 可以包含模块,可以再这选择也可以之后选择 3.配置工程属性 1)需要源码的话添加VC++目录里的源目录 2)包含头文件   ...