luoguP6071 [MdOI2020] Treequery DFS序+主席树
思路自然的码农题.
显然分类讨论一下编号在 $[l,r]$ 的点与 $p$ 的子树关系.
如果都在 $p$ 的子树内就是个区间 $lca$.
否则,就二分第一个满足 $p$ 的祖先且子树内部没有 $[l,r]$ 之间的点.
二分验证的话要用主席树.
code:
#include <cstring>
#include <map>
#include <algorithm>
#include <cstdio>
#include <vector>
#define N 200008
#define ll long long
#define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
namespace seg
{
int tot;
int newnode() { return ++tot; }
struct data
{
int sum,ls,rs;
}s[N*50];
void build(int &x,int l,int r)
{
x=newnode();
if(l==r) return;
int mid=(l+r)>>1;
build(s[x].ls,l,mid),build(s[x].rs,mid+1,r);
}
int update(int x,int l,int r,int p,int v)
{
int now=newnode();
s[now]=s[x],s[now].sum=s[x].sum+v;
if(l==r) return now;
int mid=(l+r)>>1;
if(p<=mid) s[now].ls=update(s[x].ls,l,mid,p,v);
else s[now].rs=update(s[x].rs,mid+1,r,p,v);
return now;
}
int query(int x,int y,int l,int r,int L,int R)
{
if(x+y==0) return 0;
if(l>=L&&r<=R) return s[y].sum-s[x].sum;
int re=0,mid=(l+r)>>1;
if(L<=mid) re+=query(s[x].ls,s[y].ls,l,mid,L,R);
if(R>mid) re+=query(s[x].rs,s[y].rs,mid+1,r,L,R);
return re;
}
};
int n,edges,tim;
int hd[N],to[N<<1],nex[N<<1],val[N<<1];
int fa[18][N],dfn[N],st[N],ed[N],rt[N],ge[N],dep[N],dis[N];
void add(int u,int v,int c)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dfs(int u,int ff)
{
st[u]=dfn[u]=++tim,ge[tim]=u;
fa[0][u]=ff;
for(int i=1;i<18;++i) fa[i][u]=fa[i-1][fa[i-1][u]];
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dep[v]=dep[u]+1,dis[v]=dis[u]+val[i];
dfs(v,u);
}
ed[u]=tim;
}
int get_lca(int x,int y)
{
if(dep[x]!=dep[y])
{
if(dep[x]>dep[y]) swap(x,y);
for(int i=17;i>=0;--i) if(dep[fa[i][y]]>=dep[x]) y=fa[i][y];
}
if(x==y) return x;
for(int i=17;i>=0;--i) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
return fa[0][x];
}
struct node
{
int key;
node() { key=0; }
node operator+(const node &b) const
{
node c;
c.key=get_lca(key,b.key);
return c;
}
}tree[N<<2];
void build(int l,int r,int now)
{
if(l==r) { tree[now].key=l; return; }
int mid=(l+r)>>1;
build(l,mid,now<<1),build(mid+1,r,now<<1|1);
tree[now]=tree[now<<1]+tree[now<<1|1];
}
node query(int l,int r,int now,int L,int R)
{
if(l>=L&&r<=R) return tree[now];
int mid=(l+r)>>1;
if(L<=mid&&R>mid) return query(l,mid,now<<1,L,R)+query(mid+1,r,now<<1|1,L,R);
else if(L<=mid) return query(l,mid,now<<1,L,R);
else return query(mid+1,r,now<<1|1,L,R);
}
int calc(int p,int L,int R)
{
if(seg::query(rt[st[p]-1],rt[ed[p]],1,n,L,R)==R-L+1)
return dis[query(1,n,1,L,R).key]-dis[p];
else if((p>=L&&p<=R)||(seg::query(rt[st[p]-1],rt[ed[p]],1,n,L,R))) return 0;
else
{
int x=p;
// printf("qaq\n");
for(int i=17;i>=0;--i)
{
if(fa[i][x]&&seg::query(rt[st[fa[i][x]]-1],rt[ed[fa[i][x]]],1,n,L,R)==0)
x=fa[i][x];
}
int point=fa[0][x];
// 关键节点
int lca=query(1,n,1,L,R).key;
int ans=dis[p]-dis[point]+(dep[lca]>=dep[point]?dis[lca]-dis[point]:0);
return ans;
}
}
int main()
{
// setIO("input");
int i,j,Q;
scanf("%d%d",&n,&Q);
for(i=1;i<n;++i)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c),add(x,y,c),add(y,x,c);
}
dfs(1,0);
build(1,n,1);
seg::build(rt[0],1,n);
for(i=1;i<=n;++i) rt[i]=seg::update(rt[i-1],1,n,ge[i],1);
int lastans=0;
while(Q--)
{
int p,l,r;
scanf("%d%d%d",&p,&l,&r);
p^=lastans,l^=lastans,r^=lastans;
lastans=calc(p,l,r);
printf("%d\n",lastans);
}
return 0;
}

浙公网安备 33010602011771号