日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 51nod-猴猴的比赛【莫队,线段树】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

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


題目大意

給出兩顆nnn個點的樹,求有多少個點(i,j)(i,j)(i,j)對使得在兩棵樹中iii都是jjj的祖先。


解題思路

dfsdfsdfs序中一個節點的孩子是在一個連續的區間中的。所以對于第一棵樹的每個節點的區間都作為詢問,用莫隊進行排序。

之后區間每次加入一個節點我們就在線段樹中給另一棵樹該節點對應的dfsdfsdfs序位置+1+1+1,然后詢問即可。


codecodecode

#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); }

總結

以上是生活随笔為你收集整理的51nod-猴猴的比赛【莫队,线段树】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。