zoukankan      html  css  js  c++  java
  • [LOJ6145][2017 山东三轮集训 Day7]Easy

    loj

    description

    一棵树,每次给出(l,r,x),求从点(x)出发到达([l,r])中任意一点的最短距离。

    sol

    动态点分治。
    建出点分树后,在每个节点上用以点编号为下标的线段树维护出子树中所有点到他的距离。
    对于一组询问只要暴跳父亲然后查询就可以了。
    一般而言写动态点分治的时候要维护两个东西,一个是当前节点子树的信息,另一个是当前子树给上一级重心(也就是点分树上的父亲的所有贡献)方便在计算时减去。但是在这里,因为题目中要求的是(min),而重复计算不会影响结果的正确性(因为距离只可能算大不可能算小),所以只维护一棵线段树就行了。
    时间复杂度(O(nlog^2n)),注意空间复杂度也是(O(nlog^2n))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 2e5+5;
    int n,q,to[N],nxt[N],ww[N],head[N],cnt,dfn[N],tim,dep[N],st[20][N],lg[N];
    int sz[N],w[N],sum,root,vis[N],fa[N],rt[N],tot;
    struct seg{int ls,rs,mn;}t[N*150];
    void link(int u,int v,int w){
    	to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
    }
    void dfs(int u,int f){
    	st[0][dfn[u]=++tim]=dep[u];
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f){
    			dep[to[e]]=dep[u]+ww[e];dfs(to[e],u);
    			st[0][++tim]=dep[u];
    		}
    }
    int dis(int u,int v){
    	int res=dep[u]+dep[v];u=dfn[u],v=dfn[v];
    	if (u>v) swap(u,v);int k=lg[v-u+1];
    	res-=min(st[k][u],st[k][v-(1<<k)+1])<<1;
    	return res;
    }
    void getroot(int u,int f){
    	sz[u]=1;w[u]=0;
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f&&!vis[to[e]]){
    			getroot(to[e],u);
    			sz[u]+=sz[to[e]];
    			w[u]=max(w[u],sz[to[e]]);
    		}
    	w[u]=max(w[u],sum-sz[u]);
    	if (w[u]<w[root]) root=u;
    }
    void solve(int u,int f){
    	fa[u]=f;vis[u]=1;
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]]){
    			sum=sz[to[e]];root=0;
    			getroot(to[e],0);solve(root,u);
    		}
    }
    void modify(int &x,int l,int r,int p,int v){
    	if (!x) x=++tot,t[x].mn=1e9;t[x].mn=min(t[x].mn,v);
    	if (l==r) return;int mid=l+r>>1;
    	if (p<=mid) modify(t[x].ls,l,mid,p,v);
    	else modify(t[x].rs,mid+1,r,p,v);
    }
    int query(int x,int l,int r,int ql,int qr){
    	if (!x) return (int)1e9;
    	if (l>=ql&&r<=qr) return t[x].mn;
    	int mid=l+r>>1;
    	if (qr<=mid) return query(t[x].ls,l,mid,ql,qr);
    	if (ql>mid) return query(t[x].rs,mid+1,r,ql,qr);
    	return min(query(t[x].ls,l,mid,ql,qr),query(t[x].rs,mid+1,r,ql,qr));
    }
    int main(){
    	n=gi();
    	for (int i=1;i<n;++i){
    		int u=gi(),v=gi(),w=gi();
    		link(u,v,w);link(v,u,w);
    	}
    	dfs(1,0);
    	for (int i=2;i<=tim;++i) lg[i]=lg[i>>1]+1;
    	for (int j=1;j<=lg[tim];++j)
    		for (int i=1;i+(1<<j)-1<=tim;++i)
    			st[j][i]=min(st[j-1][i],st[j-1][i+(1<<j-1)]);
    	w[0]=sum=n;getroot(1,0);solve(root,0);
    	for (int i=1;i<=n;++i)
    		for (int u=i;u;u=fa[u])
    			modify(rt[u],1,n,i,dis(u,i));
    	q=gi();while (q--){
    		int l=gi(),r=gi(),u=gi(),x=u,ans=1e9;
    		while (x) ans=min(ans,query(rt[x],1,n,l,r)+dis(x,u)),x=fa[x];
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysql基础(三)存储引擎和锁
    为给定字符串生成MD5指纹
    区块链基本原理,Part-2:工作量证明和权益证明
    区块链基本原理,Part-1:拜占庭容错
    区块链挖矿 2.0
    以太坊 2.0 中的验证者经济模型,Part-2
    以太坊 2.0 中的验证者经济模型,Part-1
    Java归并排序之递归
    Python爬虫入门教程 64-100 反爬教科书级别的网站-汽车之家,字体反爬之二
    Java棋盘覆盖问题
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9236277.html
Copyright © 2011-2022 走看看