标签:front turn char 描述 分治 name ++ pen pac
题目描述:
给一棵树,$q$次询问,每次给出$l$,$r$,$x$,求点$x$到$l$,$l+1$……$r$距离的最小值。
题解:
动态点分治。
考虑树上任意一条路径经过的最高级重心只能有一个,我们可以先建出点分树,在点分树上的每个节点存当前子树所有节点到该节点距离的最小值。
对于每次查询,可以让$x$延点分树向上跳,相当于枚举路径的最高级重心。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){c=c*10+ch-‘0‘;ch=getchar();} x = f*c; } int n,hed[N],cnt; struct EG { int to,nxt,w; }e[2*N]; void ae(int f,int t,int w) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].w = w; hed[f] = cnt; } int RT[N]; struct segtree { int ls[150*N],rs[150*N],mn[150*N],tot; void insert(int l,int r,int &x,int d,int k) { if(!x)x=++tot,mn[x]=0x3f3f3f3f; mn[x]=min(mn[x],k); if(l==r)return ; int mid = (l+r)>>1; if(d<=mid)insert(l,mid,ls[x],d,k); else insert(mid+1,r,rs[x],d,k); } int query(int l,int r,int u,int ql,int qr) { if(!u)return 0x3f3f3f3f; if(l==ql&&r==qr)return mn[u]; int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,ls[u],ql,qr); else if(ql>mid)return query(mid+1,r,rs[u],ql,qr); else return min(query(l,mid,ls[u],ql,mid),query(mid+1,r,rs[u],mid+1,qr)); } }tr; int ff[N],sum,siz[N],fs[N],rt,rot,Dis[N]; bool mrk[N]; int dep[N],dis[N],son[N],top[N],fa[N]; void dfs1(int u,int f) { fa[u] = f; siz[u] = 1; dep[u] = dep[f]+1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==f)continue; dis[to]=dis[u]+e[j].w; dfs1(to,u); siz[u]+=siz[to]; if(siz[to]>siz[son[u]]) son[u]=to; } } void dfs2(int u,int Top) { top[u]=Top; if(!son[u])return ; dfs2(son[u],Top); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to!=fa[u]&&to!=son[u]) dfs2(to,to); } } int get_lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); x = fa[top[x]]; } return dep[x]<dep[y]?x:y; } int get_dis(int x,int y) { return dis[x]+dis[y]-2*dis[get_lca(x,y)]; } void dfs(int u,int f) { siz[u] = 1,fs[u] = 0; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==f||mrk[to])continue; dfs(to,u); siz[u]+=siz[to]; fs[u] = max(fs[u],siz[to]); } fs[u] = max(fs[u],sum-siz[u]); if(fs[u]<fs[rt])rt=u; } int vis[N],tmp[N]; void bfs() { queue<int>q; q.push(rt); tr.insert(1,n,RT[rt],rt,0); vis[rt] = rt,tmp[rt] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to]||vis[to]==rt)continue; tmp[to] = tmp[u]+e[j].w; tr.insert(1,n,RT[rt],to,tmp[to]); vis[to]=rt; q.push(to); } } } int get_rt(int u) { rt = 0; dfs(u,0); bfs(); mrk[u=rt] = 1; for(int j=hed[rt];j;j=e[j].nxt) { int to = e[j].to; if(mrk[to])continue; sum = siz[to]; int nxt = get_rt(to); ff[nxt] = u; Dis[nxt] = get_dis(nxt,u); } return u; } int main() { // freopen("tt.in","r",stdin); read(n); for(int f,t,w,i=1;i<n;i++) { read(f),read(t),read(w); ae(f,t,w),ae(t,f,w); } dfs1(1,0),dfs2(1,1); fs[0] = 0x3f3f3f3f; sum = n; rot=get_rt(1); int q; read(q); for(int l,r,x,i=1;i<=q;i++) { read(l),read(r),read(x); int ans = tr.query(1,n,RT[x],l,r); int x0 = x; while(ff[x]) { x = ff[x]; ans = min(ans,tr.query(1,n,RT[x],l,r)+get_dis(x0,x)); } printf("%d\n",ans); } return 0; }
标签:front turn char 描述 分治 name ++ pen pac
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10612667.html