原题传送门

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

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

下文左右就代表树的节点按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. vue 使用高德地图vue-amap组件

    首先    npm install -S vue-amap 然后在 main.js import VueAMap from 'vue-amap'; //注意不要和 AMap原始名称覆盖 Vue.use ...

  2. iOS 图文混排

    使用系统自带的NSAttributedString来处理,对于一般的图文混排已经足够了,但是,有一个缺点就是NSAttributedString并不支持gif动画.实际上,使用gif动画还是挺卡的. ...

  3. JAVA编程思想学习笔记3-chap7-9-斗之气3段

    1.子类构造器会自动调用基类的默认构造器,如果为有参数构造器,则需要手动调用 ①this(args):调用本类中的其它构造器(只能调用一次) ②super(args):调用基类带参数的构造器 2.组合 ...

  4. 一个vue的循环列表,里面的按钮的移入事件

    需求:移入的时候,互相关注变成取消关注 移入移出事件传参$event,把这个参数打印出来看就可以搞定,而不是移入的时候,文本都改变,只改变当前行 的文本 <p @mouseover=" ...

  5. (已解决)#warning:尚未配置[微信]URL Scheme:wx4868b35061f87884, 无法使用进行授权。

    #warning:尚未配置[微信]URL Scheme:wx4868b35061f87884, 无法使用进行授权. (说白了就是注册白名单) ” -canOpenURL: failed for URL ...

  6. Spark_JGroupByKey

    package core.java; import java.util.Arrays; import java.util.List; import org.apache.spark.SparkConf ...

  7. gedit emacs

    emacs常用操作: 1)C-g:退出当前命令 2)C-x C-f:搜索文件打开 3)C-s:向前搜索 C-r:向后搜索 4)C-x 2:水平分割窗口 C-x 3:竖直分割窗口 5)C-x o:切换窗 ...

  8. <<Natural Language Inference over Interaction Space >> 句子匹配

    模型结构 code :https://github.com/YichenGong/Densely-Interactive-Inference-Network 首先是模型图: Embedding Lay ...

  9. datatable的点击事件

    datatable的点击事件 在项目中遇到一个问题,在动态绑定到datatables上的数组,要是用table中的两个某一行中数据作为参数,通过鼠标点击进行获取,查阅官方文档得以解决: //首先定义一 ...

  10. codeforces 975C Valhalla Siege

    题意: 有n个巫师站成一列,每个巫师有自己的血量. 一个人射箭攻击他们,每次造成若干点伤害,巫师按照给定的顺序承受伤害,如果伤害大了,那么死掉,伤害落到下一个巫师身上. 如果一轮攻击之后,所有的巫师都 ...