xsy1230 树(tree) 点分治+线段树
Posted xiefengze1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xsy1230 树(tree) 点分治+线段树相关的知识,希望对你有一定的参考价值。
题目大意:有一棵$n$个节点的树,点的标号为$1$到$n$。树中的边有边权。给你$m$个询问,每个询问包含三个参数$l,r,pos$,你要求出标号在$l$到$r$之间的所有点中,到节点$pos$距离最近的点离$pos$有多远。
数据范围:$n,m,l,r,pos≤10^5$,强制在线。
此题我强制在线两个变量打反了,$wa$了一发。
我们考虑点分治,对于节点x,我们在节点$x$上种一个线段树,保存以$x$为跟(点分治树树根)的子树内,每个节点距离x的距离。
对于一组查询,我们直接在点分治树上从下往上条,每跳到一个节点查询一次就可以了。
时间复杂度:$O(nlog^2 n)$。
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define INF 1e9 4 using namespace std; 5 6 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},use=0; 7 void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;} 8 9 int siz[M]={0},vis[M]={0},Minn=0,minid=0,n; 10 void dfssiz(int x,int fa){siz[x]=1;for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa&&vis[e[i].u]==0) dfssiz(e[i].u,x),siz[x]+=siz[e[i].u];} 11 void dfsmin(int x,int fa,int fsiz){int maxn=fsiz-siz[x]; for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa&&vis[e[i].u]==0) dfsmin(e[i].u,x,fsiz),maxn=max(maxn,siz[e[i].u]);if(maxn<Minn) Minn=maxn,minid=x;} 12 int makeroot(int x){Minn=M; dfssiz(x,0); dfsmin(x,0,siz[x]); return minid;} 13 14 int lc[M*120]={0},rc[M*120]={0},minn[M*120]={0},root[M]={0},cnt=0; 15 void updata(int &x,int l,int r,int k,int val){ 16 if(!x) minn[x=++cnt]=INF; minn[x]=min(minn[x],val); 17 if(l==r) return; int mid=(l+r)>>1; 18 (k<=mid)?updata(lc[x],l,mid,k,val):updata(rc[x],mid+1,r,k,val); 19 } 20 int query(int x,int l,int r,int ll,int rr){ 21 if(x==0||(ll<=l&&r<=rr)) return minn[x]; 22 int mid=(l+r)>>1,res=INF; 23 if(ll<=mid) res=min(res,query(lc[x],l,mid,ll,rr)); 24 if(mid<rr) res=min(res,query(rc[x],mid+1,r,ll,rr)); 25 return res; 26 } 27 void build(int x,int fa,int dis,int &Root){ 28 updata(Root,1,n,x,dis); 29 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa&&vis[e[i].u]==0) build(e[i].u,x,dis+e[i].v,Root); 30 } 31 32 int fa[M]={0}; 33 void solve(int x,int F){ 34 x=makeroot(x); vis[x]=1; fa[x]=F; 35 build(x,0,0,root[x]); 36 for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0) solve(e[i].u,x); 37 } 38 void ReadData(){ 39 minn[0]=INF; 40 scanf("%d",&n); 41 for(int i=1;i<n;i++){ 42 int x,y,z; scanf("%d%d%d",&x,&y,&z); 43 add(x,y,z); add(y,x,z); 44 } 45 solve(1,0); 46 } 47 48 int query(int l,int r,int pos){ 49 int minn=INF; 50 for(int x=pos;x;x=fa[x]){ 51 int disnow=query(root[x],1,n,l,r); 52 int dispos=query(root[x],1,n,pos,pos); 53 minn=min(minn,dispos+disnow); 54 } 55 return minn; 56 } 57 void Solve(){ 58 int q,ans=0; scanf("%d",&q); 59 while(q--){ 60 int l,r,pos; scanf("%d%d%d",&l,&r,&pos); pos^=ans; 61 printf("%d ",ans=query(l,r,pos)); 62 } 63 } 64 65 int main(){ 66 ReadData(); 67 Solve(); 68 }
以上是关于xsy1230 树(tree) 点分治+线段树的主要内容,如果未能解决你的问题,请参考以下文章