51nod-猴猴的比赛【莫队,线段树】

mac2026-06-10  1

正题

题目链接:https://www.51nod.com/Contest/Problem.html#contestProblemId=1150


题目大意

给出两颗 n n n个点的树,求有多少个点 ( i , j ) (i,j) (i,j)对使得在两棵树中 i i i都是 j j j的祖先。


解题思路

d f s dfs dfs序中一个节点的孩子是在一个连续的区间中的。所以对于第一棵树的每个节点的区间都作为询问,用莫队进行排序。

之后区间每次加入一个节点我们就在线段树中给另一棵树该节点对应的 d f s dfs dfs序位置 + 1 +1 +1,然后询问即可。


c o d e code code

#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> using namespace std; const int N=110000; struct edge_node{ int to,next; }e1[N*2],e2[N*2]; struct tree_node{ int l,r,w,lazy,num; }; struct ques_node{ int l,r,id,pos; }q[N]; bool cmp(ques_node x,ques_node y){ return x.pos<y.pos||(x.pos==y.pos&&x.r<y.r); } int n,tot1,tot2,cnt,w,t,ans; int dfn1[N],rfn1[N],ed1[N],ls1[N]; int dfn2[N],rfn2[N],ed2[N],ls2[N]; struct LineTree{ tree_node t[N*4]; void Build(int x,int l,int r) { t[x].l=l;t[x].r=r; if(l==r)return; int mid=(l+r)/2; Build(x*2,l,mid); Build(x*2+1,mid+1,r); } int Ask(int x,int l,int r) { if(t[x].l==l&&t[x].r==r) return t[x].w; int mid=(t[x].l+t[x].r)/2; if(r<=mid) return Ask(x*2,l,r); if(l>mid) return Ask(x*2+1,l,r); return Ask(x*2,l,mid)+Ask(x*2+1,mid+1,r); } void Change(int x,int pos,int num) { if(t[x].l==t[x].r) {t[x].w+=num;return;} if(pos<=t[x*2].r) Change(x*2,pos,num); else Change(x*2+1,pos,num); t[x].w=t[x*2].w+t[x*2+1].w; } }Tree; void add1(int x,int y) { e1[++tot1].to=y; e1[tot1].next=ls1[x]; ls1[x]=tot1; } void add2(int x,int y) { e2[++tot2].to=y; e2[tot2].next=ls2[x]; ls2[x]=tot2; } void dp1(int x,int fa) { rfn1[x]=++cnt;dfn1[cnt]=x; for(int i=ls1[x];i;i=e1[i].next){ int y=e1[i].to; if(y==fa) continue; dp1(y,x); } ed1[x]=cnt; } void dp2(int x,int fa) { rfn2[x]=++cnt;dfn2[cnt]=x; for(int i=ls2[x];i;i=e2[i].next){ int y=e2[i].to; if(y==fa) continue; dp2(y,x); } ed2[x]=cnt; } int main() { scanf("%d",&n);t=sqrt(n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add1(x,y);add1(y,x); } for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add2(x,y);add2(y,x); } dp1(1,1);cnt=0;dp2(1,1); Tree.Build(1,1,n); for(int i=1;i<=n;i++) q[i].l=rfn1[i],q[i].r=ed1[i],q[i].id=i,q[i].pos=(q[i].l-1)/t+1; sort(q+1,q+1+n,cmp); int l=1,r=0; for(int i=1;i<=n;i++) { while(l>q[i].l) Tree.Change(1,rfn2[dfn1[--l]],1); while(r<q[i].r) Tree.Change(1,rfn2[dfn1[++r]],1); while(l<q[i].l) Tree.Change(1,rfn2[dfn1[l++]],-1); while(r>q[i].r) Tree.Change(1,rfn2[dfn1[r--]],-1); ans+=Tree.Ask(1,rfn2[q[i].id],ed2[q[i].id])-1; } printf("%d",ans); }
最新回复(0)