传送门

感觉这是一个写的很舒服的题?

树上路径的交什么的就很想树上差分?发现根本没法做...它还要求在线....


好先来看\(Subtask\)吧\(qwq\)...

Subtask 1

\(l=r\),就是每次询问树上两点之间的距离...这个\(LCA\)啥的搞一搞就好了。

目前得分\(8\)分。。。

Subtask 2

\(p = 1\)?也就是说\(l...r\)这些点都在\(p\)里面,脑补一下答案就是\(p\)到\(LCA(l...r)\)的距离。

结合Subtask1,就可以拿到\(28\)分的好成绩......

Subtask 3

\(n \le 10^3\)。。。怎么暴力怎么写吧。。。

我们目前收获了\(48\)的好成绩...

Subtask 4

\(n \le 10^5\)。。。并不知道满分做法以外的做法。。。

然后放弃了希望,48分跑路。。。


讲\(100\)分的方法吧(下面默认以\(1\)号结点为根)

\(Subtask2\)感觉很有启发......如果\(l...r\)都在\(p\)的字数内的话,那么答案就是\(dist(p, LCA(l..r))\)(\(dist(x,y)\)表示树上\(x,y\)的距离)

那如果不在呢?

显然如果\(l...r\)一部分在\(p\)的子树内,一部分不在的话答案就是\(0\)。

所以只会有两种情况

  • \(l...r\)全部在\(p\)的子树内,答案为\(dist(p, LCA(l..r))\)
  • \(l...r\)全部在\(p\)的子树外

来想第二种好了。

答案也是\(dist(p,LCA(l..r))\)吗?显然毒瘤出题人不可能让你秒了题没有这么简单。

丑图警告!

由上面那张图可以知道,这时候的答案是\(p\)到\(LCA(p,l),LCA(p,l+1)...LCA(p,r)\)这些节点的最短距离(也就是到这\(r-l+1\)个点中深度最大的点的距离)

这样就对了吗?没有。。。

下面为了方便令\(x\)表示\(LCA(p,l),LCA(p,l+1)...LCA(p,r)\)中深度最大的点。

注意到上图,这些\(l..r\)所在的子树中有两棵挂在\(p\)到根的链上,那如果必定要跨越更节点呢?

脑补一下可以知道,这时候\(LCA(l..r)\)的深度一定是大于\(x\)的深度的,而上面的情况则是小于。

所以这个情况下答案是\(dist(p,LCA(l..r))\)。

总结一下,如果\(l...r\)都在\(p\)的子树外面,那么答案就是点\(p\)到\(LCA(p,l),LCA(p,l+1)...LCA(p,r)\)和\(LCA(l...r)\)这些节点中深度最大的节点的距离。


好,分类讨论了一波我们似乎得到了结论,但咋写啊。。。

考虑如何查询一个点是否在另一个点的子树内

因为\(Dfs\)序中,一个子树对应一个区间,我们只要查询这个区间内是否包含某些点就好了。

对\(Dfs\)序建出主席树就好啦!

我们还要询问\(l...r\)这些节点的\(lca\),因为\(lca\)也是可合并的,所以用线段树查询。

等等。。。那还要查\(LCA(p,l),LCA(p,l+1)...LCA(p,r)\)中深度最大的点啊。。。

这个有两种方法,一种是倍增向上跳父亲,然后主席树\(check\)。

另一种是树剖过后向上跳链,然后对每个重链二分,同样的主席树\(check\)

第二种方法应该会比第一种快。。。没写。。。还是写了倍增。。。

但是我lca是树剖求的啊。。。亏了qwq

总复杂度\(O(n \log^2 n)\)

所以下面是一个憨批写的又长又慢,\(lca\)用了树剖,但最后查询是用倍增的超大常数代码。。。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct edge{
int to,nxt,w;
}e[N<<1];
int fst[N],cnt;
inline void ade(int x,int y,int w){
e[++cnt]=(edge){y,fst[x],w},fst[x]=cnt;
}
inline void addedge(int x,int y,int w){
ade(x,y,w),ade(y,x,w);
}
int dis[N],dfn[N],id[N],size[N],fa[N],top[N],son[N],dep[N],idx=0,anc[N][23];
void dfs1(int x,int prev,int deep,int dd){
dfn[x]=++idx,id[idx]=x,dep[x]=deep,size[x]=1;
anc[x][0]=fa[x]=prev,size[son[x]=0]=-1,dis[x]=dd;
for(int i=1;i<=18;i++)
anc[x][i]=anc[anc[x][i-1]][i-1];
for(int i=fst[x];i;i=e[i].nxt){
int v=e[i].to; if(v==prev) continue;
dfs1(v,x,deep+e[i].w,dd+1),size[x]+=size[v];
if(size[v]>size[son[x]]) son[x]=v;
}
}
void dfs2(int x,int topf){
top[x]=topf; if(son[x]){
dfs2(son[x],topf);
for(int i=fst[x];i;i=e[i].nxt){
int v=e[i].to; if(v==fa[x]||v==son[x])continue;
dfs2(v,v);
}
}
}
int getlca(int x,int y){
for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
return dep[x]<dep[y]?x:y;
}
int getdist(int x,int y){
int lca=getlca(x,y);
return 1ll*dep[x]+1ll*dep[y]-2ll*dep[lca];
}
struct node{
int l,r,lca;
}t[N<<2];
inline void pushup(int x){
t[x].lca=getlca(t[x<<1].lca,t[x<<1|1].lca);
}
void build(int x,int l,int r){
t[x]=(node){l,r,0};
if(l==r){t[x].lca=l;return;} int mid=(l+r)>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
pushup(x);
}
int qry(int x,int ql,int qr){
int l=t[x].l,r=t[x].r;
if(ql<=l&&r<=qr){return t[x].lca;}
int mid=(l+r)>>1;
if(qr<=mid) return qry(x<<1,ql,qr);
else if(mid<ql) return qry(x<<1|1,ql,qr);
else return getlca(qry(x<<1,ql,qr),qry(x<<1|1,ql,qr));
}
struct Segtree{
int lc[N*40],rc[N*40],sum[N*40],cnt;
void ins(int pre,int &x,int l,int r,int p,int v=1){
x=++cnt,lc[x]=lc[pre],rc[x]=rc[pre],sum[x]=sum[pre]+v;
if(l==r)return; int mid=(l+r)>>1;
if(p<=mid) ins(lc[pre],lc[x],l,mid,p,v);
else ins(rc[pre],rc[x],mid+1,r,p,v);
}
void build(int &x,int l,int r){
x=++cnt,sum[x]=lc[x]=rc[x]=0; if(l==r)return;
int mid=(l+r)>>1; build(lc[x],l,mid),build(rc[x],mid+1,r);
}
int qry(int x,int y,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return sum[y]-sum[x]; int mid=(l+r)>>1,ret=0;
if(ql<=mid) ret+=qry(lc[x],lc[y],l,mid,ql,qr);
if(mid<qr) ret+=qry(rc[x],rc[y],mid+1,r,ql,qr);
return ret;
}
}T;
int rt[N],n,Q;
void init(){
dfs1(1,0,0,1),dfs2(1,1);
T.build(rt[0],1,n); build(1,1,n);
for(int i=1;i<=idx;i++) T.ins(rt[i-1],rt[i],1,n,id[i]);
}
int main(){
scanf("%d%d",&n,&Q);
for(int i=1,x,y,w;i<n;i++) scanf("%d%d%d",&x,&y,&w),addedge(x,y,w);
init();
int lastans=0; while(Q--){
int p,l,r; scanf("%d%d%d",&p,&l,&r);
p^=lastans,l^=lastans,r^=lastans;
int k1=T.qry(rt[dfn[p]-1],rt[dfn[p]+size[p]-1],1,n,l,r);
if(k1==r-l+1){printf("%d\n",lastans=dep[qry(1,l,r)]-dep[p]);continue;}
if(k1!=0){lastans=0,puts("0");continue;}
int x=p; for(int i=18;i>=0;i--){
int nxt=anc[x][i]; if(!nxt) continue;
if(T.qry(rt[dfn[nxt]-1],rt[dfn[nxt]+size[nxt]-1],1,n,l,r)==0) x=nxt;
}
x=fa[x];
int lca=qry(1,l,r);
if(dis[lca]>dis[x]) printf("%d\n",lastans=getdist(p,lca));
else printf("%d\n",lastans=dep[p]-dep[x]);
}
return 0;
}

[题解] LuoguP6071 [MdOI2020] Treequery的更多相关文章

  1. 题解 【[MdOI2020] Decrease】

    \[ \texttt{Preface} \] 感觉 C 比 B 还简单? \[ \texttt{Description} \] 给定一个 \(n×n\) 的矩阵,你可以进行若干次操作. 每次操作,你可 ...

  2. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  3. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  4. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  5. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  6. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  7. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  8. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  9. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

随机推荐

  1. 阿里云CentOS安装图形化界面

    阿里云提供的linux系统是不含图形化界面的,如果您需要安装图形化界面, 请您参考为Linux实例安装图形化桌面环境和在CentOS系统中自动安装并运行VNC Server安装部署一下. 为Linux ...

  2. monkey常见API及实例

    一.API简介 LaunchActivity(pkg_name, cl_name):启动应用的Activity.参数:包名和启动的Activity. Tap(x, y, tapDuration): 模 ...

  3. 为何以及如何学Linux系统?

    在当今的社会中,linux用处实在是太过广泛了.现在用在服务器和嵌入式上的Linux发行版本数不胜数,桌面上linux只占1%的比例,但这不代表linux比windows和mac 做得差,实际上桌面系 ...

  4. video-player

    1. VLC 2. MPlayer 3. FFmpeg 4. 显示媒体信息 5. 视频播放器软件比较 1. VLC https://www.videolan.org/vlc/ https://en.w ...

  5. 解题报告+板子:luogu P3387 【模板】缩点

    题目链接:P3387 [模板]缩点 缩点板子,所谓\(dp\)就是拓扑排序(毕竟可以重走边),像\(SPFA\)一样松弛就好,就是重边极其烦人,还加了排序(绝对自己想的,然鹅拓扑的思路不是). 下面上 ...

  6. redis中关闭rdb跟aof

    https://zm10.sm-tc.cn/?src=l4uLj8XQ0IiIiNGdip2KlJDRnJCS0JaRmZCbmouelpPSzc%2FJz8vJxtGXi5KT&uid=49 ...

  7. P1091合唱队形(LIS问题)

    题目描述(题目链接:https://www.luogu.org/problem/P1091) NN位同学站成一排,音乐老师要请其中的(N-KN−K)位同学出列,使得剩下的KK位同学排成合唱队形. 合唱 ...

  8. 「USACO08JAN」电话线Telephone Lines

    传送门 Luogu 解题思路 考虑二分,每次把大于二分值的边的权设为1,小于等于的设为0,如果最短路<=k则可行,记得判无解 细节注意事项 咕咕咕 参考代码 #include <algor ...

  9. 「HNOI2008」玩具装箱

    传送门 Luogu 解题思路 \(\text{DP}\) 很显然: 设 \(dp_i\) 表示前 \(i\) 个玩具的最小费用,转移就是: \(dp_i = \max\limits_{0\le j & ...

  10. scikit_learn (sklearn)库中NearestNeighbors(最近邻)函数的各参数说明

    NearestNeighbors(n_neighbors=5, radius=1.0, algorithm='auto', leaf_size=30, metric='minkowski', p=2, ...