首页 > 其他分享 >题解 洛谷P3398 仓鼠找 sugar

题解 洛谷P3398 仓鼠找 sugar

时间:2024-09-25 20:37:32浏览次数:8  
标签:洛谷 int 题解 tree add tag lp P3398 rp

原题链接P3398 仓鼠找 sugar

题解里大部分都是用的lca,然而我看不懂那些关于lca的性质是怎么证明出来的。

不过这题可以直接用树链剖分来写,把模板套上去就好了。

题意为查找两条路径是否存在公共点,我们只需要把其中一条路径上的点都赋值为1,然后查询另一条路径上的点的总和,如果总和大于0,说明那条路径经过了这条路径,即这两条路径有公共点。查询完以后要记得将刚才赋值的1减去,防止对后面的查询产生干扰。

会树链剖分的话应该很好理解。

#include<bits/stdc++.h>
#define lp p<<1
#define rp p<<1|1
using namespace std;
const int N=1e5+10;
int n,q;
struct edge{
	int v,nxt;
}e[N<<1];
int fir[N],tot=0;
void add_edge(int u,int v){
	e[++tot].v=v;
	e[tot].nxt=fir[u];
	fir[u]=tot;
}
int fa[N],son[N],dep[N],siz[N];
void dfs(int u,int f){
	fa[u]=f;
	son[u]=0;
	dep[u]=dep[f]+1;
	siz[u]=1;
	for(int i=fir[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==f)continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])son[u]=v;
	}
}
int dfn[N],id[N],top[N],times=0;
void hld(int u,int topf){
	dfn[u]=++times;
	id[dfn[u]]=u;
	top[u]=topf;
	if(!son[u])return;
	hld(son[u],topf);
	for(int i=fir[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fa[u]||v==son[u])continue;
		hld(v,v);
	}
}
namespace Segment_Tree{
	struct node{
		int s,t,sum,tag;
	}tree[N<<2];
	void maintain(int p){
		tree[p].sum=tree[lp].sum+tree[rp].sum;
	}
	void build(int l,int r,int p){
		tree[p].s=l;
		tree[p].t=r;
		tree[p].tag=0;
		if(l==r){
			tree[p].sum=0;
			return;
		}
		int mid=l+r>>1;
		build(l,mid,lp);
		build(mid+1,r,rp);
		maintain(p);
	}
	void pushdown(int p){
		if(tree[p].tag){
			tree[lp].sum+=tree[p].tag*(tree[lp].t-tree[lp].s+1);
			tree[rp].sum+=tree[p].tag*(tree[rp].t-tree[rp].s+1);
			tree[lp].tag+=tree[p].tag;
			tree[rp].tag+=tree[p].tag;
			tree[p].tag=0;
		}
	}
	void update(int l,int r,int c,int p){
		if(tree[p].s>=l&&tree[p].t<=r){
			tree[p].sum+=(tree[p].t-tree[p].s+1)*c;
			tree[p].tag+=c;
			return;
		}
		pushdown(p);
		int mid=tree[p].s+tree[p].t>>1;
		if(l<=mid)update(l,r,c,lp);
		if(r>mid)update(l,r,c,rp);
		maintain(p);
	} 
	int ask(int l,int r,int p){
		if(tree[p].s>=l&&tree[p].t<=r)return tree[p].sum;
		pushdown(p);
		int mid=tree[p].s+tree[p].t>>1,ans=0;
		if(l<=mid)ans+=ask(l,r,lp);
		if(r>mid)ans+=ask(l,r,rp);
		return ans;
	}
}
using namespace Segment_Tree;
void add_chain(int u,int v,int w){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		update(dfn[top[u]],dfn[u],w,1);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	update(dfn[v],dfn[u],w,1);
}
int ask_chain(int u,int v){
	int ans=0;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		ans+=ask(dfn[top[u]],dfn[u],1);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	ans+=ask(dfn[v],dfn[u],1);
	return ans;
} 
int main(){
	cin>>n>>q;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		add_edge(u,v);
		add_edge(v,u);
	}
	dfs(1,0);
	hld(1,1);
	build(1,n,1);
	for(int i=1;i<=q;i++){
		int a,b,c,d;
		cin>>a>>b>>c>>d;
		add_chain(a,b,1);
		if(ask_chain(c,d))puts("Y");
		else puts("N");
		add_chain(a,b,-1);
	}
	return 0;
}

标签:洛谷,int,题解,tree,add,tag,lp,P3398,rp
From: https://www.cnblogs.com/loynyng-fasfy/p/18432124

相关文章

  • [ARC062F] AtCoDeerくんとグラフ色塗り 题解
    思路对于一个点双,我们可以发现:假如它是一个简单环,那么它只能旋转这一个环,我们可以使用polya定理计算。假如它是多个环的组成,那么它的颜色可以随意调动,任何的情况都可以得到,那么假如说有\(m\)条边,方案数则为\(\binom{m+k-1}{k-1}\),我们只考虑每一种颜色的出现次数。对于......
  • 题解 QOJ5034【>.<】/ BC2401D【可爱路径】
    必可赛前公益众筹赛第一试Dhttps://qoj.ac/problem/5034,2022-2023集训队互测Round6(Nov12,2022)题目描述这原本是一道简单的最短路问题,但是由于种种地域文化,宗教信仰以及政治因素,原来一些或许可以行走的路径不能通行了。我们定义禁止路径为连续的经过一些特定的点的......
  • Luogu_P10977(AcWing_299) Cut the Sequence 题解
    解题思路考虑线性dp。首先如果存在\(a_i>m\),那肯定不满足条件,输出\(-1\)。设\(f_i\)表示前\(i\)个数分成若干段,然后每段最大数之和,其中每段内的整数之和不超过\(m\)。\(f_i\)肯定是由\(f_j\)(\(1\lej<i\))转移过来的,也就是前\(j\)个数分好后再加上\((j,i]\)这一......
  • 【OJ题解-1】稀疏矩阵乘法
    一、试题题面计算两个稀疏矩阵相乘,输出相乘的结果【输入输出约定】输入:第一行输入三个正整数p、q、r,表示p×q和q×r的两个矩阵相乘;(约定0<p,q,r≤1000)然后是第一个矩阵的输入,首先是一个整数m,表示矩阵一有m个非零元素;然后是m行,每行三个整数i,j,d,表示第i行,第j列的元素为d(约定......
  • P8906 [USACO22DEC] Breakdown P 题解
    P8906[USACO22DEC]BreakdownP题解显然的套路是删边转化为加边。考虑到维护整条路径不好维护,于是考虑转化维护\(f_{i,k},g_{i,k}\)分别表示\(1,n\)到\(i\)走了\(k\)步时的最短路。那么此时\(k\le4\)。我们先考虑\(f\)的转移,\(g\)的转移是等价的。那么对于\((......
  • 题解:CF573D Bear and Cavalry
    因为这是远古题目,所以根据现在的评测机速度,用\(O(nq)\)的做法也是可以过的。也就是说,我们可以每次操作直接修改对应位置上的数字,然后设计一种\(O(n)\)的算法求解答案。这道题类似资源分配型动态规划,所以我们可以设\(dp_i\)表示分配前\(i\)个人的答案。直接写是不行的,我......
  • 题解:AT_abc204_e [ABC204E] Rush Hour 2
    变形的dijkstra。先思考什么情况下需要等待以及等待多长时间最优。我们把题目上的计算方法按照当前的时间\(t\)和通过所需的时间\(f(t)\)列个函数关系:\[f(t)=t+c+\lfloor\frac{d}{t+1}\rfloor\]然后用Desmos画个图可以得到图像(其实就是对勾函数):因为\(c,d\geq0\),所......
  • [湖北省选模拟 2023] 棋圣 / alphago 题解
    很牛的题目啊。-Alex_Wei发现这个操作比较复杂但限制较弱,考虑通过考察“不变的量”来刻画操作。容易发现若为二分图,则初始颜色不同的一定不能移动到一起。又因为在存在环的图上这个限制很弱/目前较难考虑,所以先考虑树的情况,发现答案存在可能取到的上界,令\(c_{i,j}\)为初......
  • CF1119H Triple 题解
    DescriptionSK酱送给你了一份生日礼物。礼物是\(n\)个三元组\((a_i,b_i,c_i)\)和四个正整数\(x,y,z,k\)。你利用这\(n\)个三元组填充了\(n\)个数组,其中第\(i\)个数组中有\(x\)个\(a_i\),\(y\)个\(b_i\),\(z\)个\(c_i\)(所以第\(i\)个数组长度为\((x+y+z)\)。......
  • Codeforces Round 974 (Div. 3)题解记录
    A.RobinHelps签到模拟,遍历一遍即可,注意没钱时不给钱。\(O(n)\)#include<iostream>#include<set>#include<map>#include<vector>#include<algorithm>#include<bitset>#include<math.h>#include<string>#include<string.h>#......