lca

luogu P2597 [ZJOI2012]灾难

笑着哭i 提交于 2019-12-01 10:19:37
这道题好仙啊,不过暴力都能拿70pts。 考虑每个点的贡献,会发现,它只对它所有食物的LCA及LCA到根的路径上的节点有灾难值为一的贡献。 然后就是建树啦,我们必须保证当前节点的所有食物都已建好树,所以top_sort,在更新入度到为零时,就求出它所有食物的LCA, 然后将LCA做为此节点的父节点,并令sum(lca)++,更新ST表。。。 最后还要统计节点对LCA到根的节点的贡献,做一次树上前缀和即可。 这个玩意什么时候叫做树上前缀和了QAQ。。其实特别low。 代码较丑,搞了三个链式前向星,最后还因为超级源点的深度和生产者的深度都赋成了 1 卡了半天。。。。 Code: #include<iostream> #include<cstdio> #include<queue> #define N 100000 using namespace std; queue<int> q; int n,Head[N],ver[N],nex[N],du[N],f[N][21],d[N],tot,sum[N]; int Head2[N],ver2[N],nex2[N],tot2; int Head3[N],ver3[N],nex3[N],tot3; inline int read(){ char c=getchar();int x=0,flag=1; while(c<'0' || c>'9')

codeforces 1149c

一世执手 提交于 2019-12-01 10:14:56
给出了()的字符串,这里的()字符串可以看成是dfs序列,再求lca时的那张表。 所以这一个序列就可以看成是在dfs序上面,求树的直径。 取某一段[l,r],可以知道lca一定在[l,r]之间。 我们就用公式 diameter=hight[l]+height[r]-2* height[lca(l,r)]来维护两个点的之间的距离。 把(看成1,)看成-1,可以发现height[i]=sufix[i],即前缀和。 所以我们建立一颗线段树,维护hight[l]+height[r]-2* height[lca(l,r)]这个式子即可。 针对这个式子,我们一共有三种方式可以统计diameter,当前区间的diameter=max(左子树diameter,右子树diameter,跨接两个区间的diameter ) 关在在于怎么去求跨界两个区间的。我们可以维护 height[l]-2*height[lca]来得到。即左子树的 往右边方向的lca去连接右边,右子树 往左边方向走的lca去链接左边,满足l<=lca<=r,即lca在我们取的两点之间。(注意合并时还有细节,比如我们并没有直接维护前缀和,而是根节点置为深度1,不断加深度来完成,方便后面更新节点,也可以直接维护深度进行区间修改,不过要复杂一点) #include<iostream> #include<cstring> #include

LCA【模板】

故事扮演 提交于 2019-12-01 09:48:36
#include<iostream> #include<cstdio> using namespace std; struct yyy{ int t, nex; }e[2*500001]; int depth[500001],fa[500001][22],lg[500001],head[500001]; int tot; void add(int x,int y) //邻接表存树 { e[++tot].t=y; e[tot].nex=head[x]; head[x]=tot; } void dfs(int f,int fath) { depth[f]=depth[fath]+1; fa[f][0]=fath; for(int i=1;(1<<i)<=depth[f];i++) fa[f][i]=fa[fa[f][i-1]][i-1]; for(int i=head[f];i;i=e[i].nex) if(e[i].t!=fath) dfs(e[i].t,f); } int lca(int x,int y) { if(depth[x]<depth[y]) swap(x,y); while(depth[x]>depth[y]) x=fa[x][lg[depth[x]-depth[y]]-1]; if(x==y) return x; for(int k=lg[depth[x]]-1;k>

BZOJ2286 消耗战

末鹿安然 提交于 2019-12-01 08:24:59
[ 传送门 ] 如果只有单次询问,可以直接树形DP $f\left[u\right]$表示以$u$为根的子树中所有资源丰富的岛屿不与$u$联通的最小代价 转移方程显然 若儿子节点$v$为资源丰富的岛屿 $f\left[u\right] = f\left[u\right] + w\left[u, v\right]$ 若儿子节点$v$不是资源丰富的岛屿 $f\left[u\right] = f\left[u\right] + min\left(w\left[u, v\right], f\left[v\right]\right)$ 这样下来时间复杂度是$O(n\times q)$。 但是可以发现,资源丰富的点的总和是与$n$同阶的,也就是询问很多的情况下,其实这些 关键点 是很少的,整棵树我们是没有必要遍历一遍的,那么就引入 虚树 ( Virtual tree )这个概念。 其实就是把关键点和关键点之间的LCA保存下来,被删掉的点之间边的信息用某种方式保留下来,比如这道题中被删掉的点之间的边权,用取$min$的方式保存在保留下来的边中,因为若一条链上没有关键点,其叶子才是关键点,那么中间这条长链选择删哪条边都可以,为了使代价最小,显然删权值最小的边。 建树就是板子了。维护以dfs序为权值的单调栈,pop的过程连边,发现LCA未在栈里及时加进去即可。详见[ OI Wiki - 虚树 ]

洛谷 P3398 仓鼠找sugar

三世轮回 提交于 2019-12-01 07:23:40
传送门 题目分析: 就是给你两条路径的起点和终点,然后让你查找这两条路径有没有交点 if(有)puts("Y"); else puts("N"); 解题思路: 很明显,是让我们求lca,我们先求出A与B的lca和C与D的lca, 然后我们在{A,C}{A,D}{B,C}{B,D}的lca的深度中找一个最大的, 然后与上述两个lca的深度比较,然后如果深度的最大值比两个lca的深度大的话, 那么就输出“Y”,然后不满足上边的情况那就输出“N”. code #include <bits/stdc++.h> #define N 500010 #define M 1010 using namespace std; int n, m, head[N], fa[N][21], deep[N]; int add_edge; bool vis[N]; struct node { int next, to; }edge[N << 1]; int read() { int s = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar(); return f ? -s : s

洛谷$P4211\\ [LNOI2014]\\ LCA$ 树链剖分+线段树

為{幸葍}努か 提交于 2019-12-01 06:11:49
正解:树剖+线段树 解题报告: 传送门$QwQ$ 看到$dep[lca]$啥的就想到之前托腮腮$CSP$模拟$D1T3$的那个套路,,, 然后试下这个想法,于是$dep[lca(x,y)]=\sum_{i=1}^{\infty}[i\leq dep[lca(x,y)]]$,就可以是,从$x$到根全部加一然后查询$y$到根的权值和. 现在变成$\sum_{i=l}^r dep[lca(i,x)]$,那就$l$到$r$到根全加一然后查询$x$到根的权值和. 显然考虑差分呗?就$1$到$r$全加一的权值和减去$1$到$l-1$全加一的权值和. 于是就从$1$枚举到$n$每次从当前节点到根全加一,顺便维护下这个答案就完事$QwQ$ 来源: https://www.cnblogs.com/lqsukida/p/11664263.html

CSP-S模拟68 题解

天涯浪子 提交于 2019-12-01 04:50:32
T1: 不难想到贪心,但是怎么贪,他有两个限制条件,所以不是很好搞,所以用一个类似与wqs二分的思路 我可能在口胡 ,因为你肯定要把最小的给删掉,所以你限定一个x或y,然后在选出另一个限制,所以要同时维护删$k$个$x$最小和$y$最小,一个排序预处理,一个用堆维护即可。注意边界问题,思考实际意义。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 const int N=1e5+10; 5 int a[N]; 6 priority_queue<int> qx,qy; 7 struct node{ 8 int x,y; 9 bool friend operator < (node a,node b){ 10 return a.x==b.x?(a.y<b.y):(a.x<b.x); 11 } 12 }p[N]; 13 signed main(){ 14 int T; 15 scanf("%lld",&T); 16 while(T--){ 17 int n,m; 18 scanf("%lld%lld",&n,&m); 19 priority_queue<int,vector<int>,greater<int> >q; 20 for(int i=1;i<=n;++i){ 21 scanf(

[GDOI2016]疯狂动物城

别来无恙 提交于 2019-11-30 21:32:19
\(u \in [X,LCA] : val[u] \cdot {(dep[u]+dep[Y]-2dep[LCA])(dep[u]+dep[Y]-2dep[LCA]+1) \over 2}\) \(=val[u]\cdot{[dep[Y](dep[y]+1)-2dep[LCA](2dep[Y] -2dep[LCA]+1)]+dep[i](1+2dep[y]-4dep[LCA])+dep^2[i] \over 2}\) \(u \in [LCA,Y] : {val[u] \cdot (dep[Y]-dep[i])(dep[Y]-dep[i]+1) \over 2}\) \(= val[u] \cdot {dep[Y](dep[Y]+1)-dep[i](1+2dep[Y]) + dep^2[i]\over 2}\) 来源: https://www.cnblogs.com/youddjxd/p/11641149.html

「UR#5」怎样更有力气

微笑、不失礼 提交于 2019-11-30 19:40:01
「UR#5」怎样更有力气 解题思路 考虑没有限制的情况,一定是把操作离线下来,按照边权从小到达做。可以发现,如果没有限制,完全图是多余的,直接拿树边进行合并就可以了。我们要做这么一件事情,把每个点属于的图上联通块看做颜色,每次合并链上相邻两块颜色不一样的,那么我们再额外使用一个并查集,把树上相邻的颜色相同的点合并在一个集合里,每次跳到集合中最浅的点做图上的合并操作即可,复杂度 \(\mathcal O(n\alpha(n))\) 。 考虑一个操作的限制数量 \(cnt\) ,如果 \(cnt \geq\) 链上的点数,那么这些点仍然是联通的,所以可以直接当做没有限制的情况来做。于是发现,有限制的情况的链的点数不超过 \(p_i\) ,考虑暴力把这条链上的点拿出来。问题转化为有一个点集 \(S\) ,并且给出这个点集的补图,要合并联通块信息。涉及到补图可以试图用一个小技巧解决,拿出补图中度数最小的点 \(x\) ,有 \(\deg[x]\leq \min(|S|,\sqrt{p_i})\) 。划分成与 \(x\) 相连的点集和与 \(x\) 不相邻的点集两个问题考虑。所有不与 \(x\) 相连的点可以直接与 \(x\) 合并,所有与 \(x\) 相邻的点不超过 \(\sqrt{p_i}\) 个,可以直接枚举两个点合并。对于两个集合直接的连边,考虑与 \(x\) 相邻的集合的每一条对

【[HNOI/AHOI2018]毒瘤】

不羁岁月 提交于 2019-11-30 19:23:57
思路非常精妙的一道虚树题 简单题意:给一张图,求这张图上的独立集数量 对于一棵树的情况,可以设 \(dp_{u,0/1}\) 表示节点 \(u\) 选/不选的方案数 显然有: \[dp_{u,0}=\prod (dp_{v,1}+dp_{v,0})\] \[dp_{u,1}=\prod dp_{v,0}\] 接下来考虑非树边 正常 \(dp\) 的话那么转移应该是 \(O(n)\) 的 我们发现非树边很少,所以可以预处理出来,然后枚举其连接的两点之间的状态 不难发现状态只有如下三种: \((0,0),(0,1),(1,0)\) 可以发现 \((0,0)\) 和 \((0,1)\) 可以合并 于是我们就只需要枚举所有的非树边其连接的 \(\rm dfn\) 较小的点的状态就可以了 复杂度 \(O(n*2^{11})\) 可以得到 \(75pts\) 的高分 接下来是一个很妙的做法: 我们可以考虑将所有非树边上的点拿下来建虚树 这应该是一个大小 \(\le(44+1)\) 的虚树 注意到,我们的 \(dp\) 转移本应如此: \[dp_{u,0}=\prod (dp_{v,1}+dp_{v,0})\] \[dp_{u,1}=\prod dp_{v,0}\] 但是放在虚树上这样显然是错的 我们发现虚树是维护了点之间的关系并构建了其 \(lca\)