洛谷 P3398 仓鼠找sugar —— 树链剖分
题目:https://www.luogu.org/problemnew/show/P3398
树链剖分一下,路径就变成线段树上的几个区间;
两条路径相交就是线段树上有区间相交,所以在相应位置打个标记,查询有无标记即可;
一开始是打1的标记,查询后就减去,查询 sum 是否为 0 即可;
然而这样写却全 WA 了...悲痛欲绝去看了 TJ ,模仿了其写法,回头再看发现是忘记写 pushdown ,而且 -1 的地方写成 0 了囧...
改掉就 A 了,这个做法完全没问题嘛!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e5+;
int n,q,hd[maxn],ct,sum[maxn<<],tim,fa[maxn],lzy[maxn<<];
int dep[maxn],dfn[maxn],top[maxn],son[maxn],siz[maxn],id[maxn];
struct N{
int to,nxt;
N(int t=,int n=):to(t),nxt(n) {}
}ed[maxn<<];
void add(int x,int y){ed[++ct]=N(y,hd[x]); hd[x]=ct;}
void dfs(int x,int f)
{
dep[x]=dep[f]+; siz[x]=; fa[x]=f;
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==f)continue;
dfs(u,x); siz[x]+=siz[u];
if(siz[u]>siz[son[x]])son[x]=u;
}
}
void dfs2(int x)
{
dfn[x]=++tim; id[tim]=x;//
if(son[x])top[son[x]]=top[x],dfs2(son[x]);
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa[x]||u==son[x])continue;
top[u]=u; dfs2(u);
}
}
void pushup(int x){sum[x]=sum[x<<]+sum[x<<|];}
void pushdown(int x,int l,int r)
{
if(!lzy[x])return;
int ls=(x<<),rs=(x<<|),mid=((l+r)>>);
lzy[ls]+=lzy[x]; lzy[rs]+=lzy[x];
sum[ls]+=lzy[x]*(mid-l+); sum[rs]+=lzy[x]*(r-mid);
lzy[x]=;
}
void add(int x,int l,int r,int L,int R,int val)
{
if(l>=L&&r<=R){sum[x]+=val*(r-l+); lzy[x]+=val; return;}
pushdown(x,l,r);//
int mid=((l+r)>>);
if(mid>=L)add(x<<,l,mid,L,R,val);
if(mid<R)add(x<<|,mid+,r,L,R,val);
pushup(x);
}
int ask(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return sum[x];
pushdown(x,l,r);//
int ret=,mid=((l+r)>>);
if(mid>=L)ret+=ask(x<<,l,mid,L,R);
if(mid<R)ret+=ask(x<<|,mid+,r,L,R);
return ret;
}
void update(int x,int y,int val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
add(,,n,dfn[top[x]],dfn[x],val);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
add(,,n,dfn[y],dfn[x],val);
}
bool query(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(ask(,,n,dfn[top[x]],dfn[x])) return ;
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
return ask(,,n,dfn[y],dfn[x]);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(,); top[]=; dfs2();
for(int i=,a,b,c,d;i<=q;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
update(a,b,);
if(query(c,d))printf("Y\n");
else printf("N\n");
update(a,b,-);//!0
}
return ;
}
还有 TJ 写法,就是不删除了,打个 int 类型的标记,所以查询 max 即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e5+;
int n,q,hd[maxn],ct,mx[maxn<<],tim,fa[maxn],lzy[maxn<<],tot;
int dep[maxn],dfn[maxn],top[maxn],son[maxn],siz[maxn],id[maxn];
struct N{
int to,nxt;
N(int t=,int n=):to(t),nxt(n) {}
}ed[maxn<<];
void add(int x,int y){ed[++ct]=N(y,hd[x]); hd[x]=ct;}
void dfs(int x,int f)
{
dep[x]=dep[f]+; siz[x]=; fa[x]=f;
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==f)continue;
dfs(u,x); siz[x]+=siz[u];
if(siz[u]>siz[son[x]])son[x]=u;
}
}
void dfs2(int x)
{
dfn[x]=++tim; id[tim]=x;//
if(son[x])top[son[x]]=top[x],dfs2(son[x]);
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa[x]||u==son[x])continue;
top[u]=u; dfs2(u);
}
}
void pushup(int x){mx[x]=max(mx[x<<],mx[x<<|]);}
void pushdown(int x)
{
if(!lzy[x])return;
lzy[x<<]=lzy[x<<|]=lzy[x];
mx[x<<]=mx[x<<|]=lzy[x];
lzy[x]=;
}
void add(int x,int l,int r,int L,int R,int val)
{
if(l>=L&&r<=R){mx[x]=lzy[x]=val; return;}
pushdown(x);
int mid=((l+r)>>);
if(mid>=L)add(x<<,l,mid,L,R,val);
if(mid<R)add(x<<|,mid+,r,L,R,val);
pushup(x);
}
int ask(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return mx[x];
pushdown(x);
int ret=,mid=((l+r)>>);
if(mid>=L)ret=max(ret,ask(x<<,l,mid,L,R));
if(mid<R)ret=max(ret,ask(x<<|,mid+,r,L,R));
return ret;
}
void update(int x,int y,int val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
add(,,n,dfn[top[x]],dfn[x],val);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
add(,,n,dfn[y],dfn[x],val);
}
bool query(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(ask(,,n,dfn[top[x]],dfn[x])==tot) return ;
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
return (ask(,,n,dfn[y],dfn[x])==tot);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(,); top[]=; dfs2();
for(int i=,a,b,c,d;i<=q;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
update(a,b,++tot);
if(query(c,d))printf("Y\n");
else printf("N\n");
}
return ;
}
洛谷 P3398 仓鼠找sugar —— 树链剖分的更多相关文章
- 洛谷 3398 仓鼠找sugar——树链剖分
题目:https://www.luogu.org/problemnew/show/P3398 原来只要把值记录成第几次就行了. 别忘了while(top[a]!=top[b])之后还要走一步. #in ...
- 洛谷 P3398 仓鼠找sugar 解题报告
P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而 ...
- 洛谷P3398 仓鼠找sugar [LCA]
题目传送门 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而 ...
- 洛谷P3398 仓鼠找sugar
题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c) ...
- 洛谷——P3398 仓鼠找sugar
https://www.luogu.org/problem/show?pid=3398#sub 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴 ...
- 洛谷 P3398 仓鼠找sugar 题解
每日一题 day44 打卡 Analysis 首先有一个结论:先找 p1=(a,b),p2=(c,d) 的LCA的深度,在与(a,c),(a,d),(b,c),(b,d)中最深的LCA n的深度比较, ...
- 洛谷 [P3398] 仓鼠找sugar
树剖求LCA 我们可以发现,两条路径ab,cd相交,当且仅当 dep[lca(a,b)]>=dep[lca(c,d)]&(lca(lca(a,b),c)==lca(a,b)||lca(l ...
- 洛谷P3412 仓鼠找$Sugar\ II$题解(期望+统计论?)
洛谷P3412 仓鼠找\(Sugar\ II\)题解(期望+统计论?) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327573 原题链接:洛谷P3412 ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
随机推荐
- ThinkPHP---案例--实现知识管理功能
[一]准备工作 (1)数据表sp_knowledge SQL语句:知识管理数据表结构 create table sp_knowledge( id int(11) not null auto_incre ...
- Java怎么实现文件数据拷贝
实现一个文件的内容拷贝到另一个文件里 public void copyDemo () throws IOException { //创建文件输入流 FileInputStream fis = new ...
- 集合:Collection
why ? when ? how ? what ? Java 集合框架图 由上图我们可以看到,Java 集合主要分为两类:Collection 和 Map. Collection 接口 遍历 Coll ...
- Python学习——集合
集合 python中的集合和数学上集合具有基本相同的性质,此处不再赘述. 1.创建集合的两种方法 #直接创建 num={1,2,3,4,5} #利用set方法创建 num1=set([1,2,3,4, ...
- 爬楼梯,N级楼梯有多少种走法?
https://blog.csdn.net/tcpipstack/article/details/45173685 一个人爬楼梯,一步可以迈一级,二级,三级台阶,如果楼梯有N级,要求编写程序,求总共有 ...
- SQL函数小记
写一篇笔记,记录一下常见的sql函数,以备之后的查找需要. 算数函数 abs(num):绝对值函数 mod(被除数,除数):求余函数 round(num,保留小数的位数):四舍五入函数 字符串函数 c ...
- BZOJ 1782 洛谷 2982 [Usaco2010 Feb]slowdown 慢慢游
[题解] 一头牛走到i,相当于把i点的子树的点权都加1,查询减慢的次数就是查询目的地的点权. 预处理dfs序,某个点的子树的dfs序是连续的一段.差分后用树状数组维护,变成点修区查.或者直接线段树区修 ...
- RequestMapping_请求方式
[映射请求参数.请求方法或请求头] 1.@RequestMapping 除了可以使用请求URL 映射请求外,还可以使用请求方法.请求参数及请求头映射请求. 2.@RequestMapping 的val ...
- 【Codeforces 279C】Ladder
[链接] 我是链接,点我呀:) [题意] 题意 [题解] 设pre[i]表示i往前一直递增能递增多远 设aft[i]表示i往后一直递增能递增多远 如果aft[l]+pre[r]>=(r-l+1) ...
- Go语言语法说明
Go语言语法说明 go语言中的go func(){}() 表示以并发的方式调用匿名函数func 深入讲解Go语言中函数new与make的使用和区别 前言 本文主要给大家介绍了Go语言中函数new与ma ...