【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(n\log^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\n",ans=query(l,r,pos));
62     }
63 }
64 
65 int main(){
66     ReadData();
67     Solve();
68 }

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/10398002.html