zoukankan      html  css  js  c++  java
  • 题解 Children Trips

    题目传送门

    Description

    给出一个大小为 (n) 的边权全为 (1,2) 的带权树,有 (q) 此查询,每次给出 (u,v,p) ,问 (u o v) 每次可以最多走边权和 (le p) 的路径,问最少走多少次。

    (n,qle 10^5)

    Solution

    因为自己没有想出来,所以还是写一发题解。

    首先边权比较有迷惑性,但是这个 (le 2) 确实多少用。考虑根号分治,可以发现 (p>sqrt n) 最多只会爬 (sqrt n) 次,所以可以直接暴力爬,即倍增找到每次可以走到的下一个点。

    考虑 (sqrt n),发现我们仍可以使用倍增,即处理出一个点走 (2^i) 次会走到哪里。

    复杂度 (Theta(nsqrt nlog n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 100005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
    
    int n,m,siz;
    
    struct edge{int v,w;}; 
    vector <edge> g[MAXN];
    
    struct str{
    	int u,v,P,ind;
    	bool operator < (const str &t)const{return P < t.P;}
    }seq[MAXN];
    
    int dep[MAXN],dis[MAXN],par[MAXN][21];
    int getlca (int u,int v){
    	if (dep[u] < dep[v]) swap (u,v);
    	for (Int i = 20,dis = dep[u] - dep[v];~i;-- i) if (dis >> i & 1) u = par[u][i];
    	if (u == v) return u;
    	else{
    		for (Int i = 20;~i;-- i) if (par[u][i] ^ par[v][i]) u = par[u][i],v = par[v][i];
    		return par[u][0];
    	}
    }
    
    void dfs (int u,int fa){
    	dep[u] = dep[fa] + 1,par[u][0] = fa;
    	for (Int i = 1;i <= 20;++ i) par[u][i] = par[par[u][i - 1]][i - 1];
    	for (edge to : g[u]){
    		int v = to.v,w = to.w;
    		if (v == fa) continue;
    		dis[v] = dis[u] + w,dfs (v,u);
    	}
    }
    
    int getjump (int u,int p){
    	for (Int i = 20;~i;-- i) if (par[u][i] && dis[u] - dis[par[u][i]] <= p) 
    //		cout << u << " -> " << par[u][i] << endl,
    		p -= dis[u] - dis[par[u][i]],u = par[u][i];
    	return u;
    }
    
    struct node{int lft,stp;};
    
    node getit1 (int u,int lca,int p){
    	int stp = 0;
    	while (u ^ lca){
    		int now = getjump (u,p);
    		if (dep[now] > dep[lca]) stp ++,u = now;
    		else break;
    	}
    	return node{dis[u] - dis[lca],stp};
    }
    
    int st[MAXN][21];
    void makeit (int P){
    	for (Int i = 1;i <= n;++ i) st[i][0] = getjump (i,P);
    //	cout << P << ": ------------ " << endl;
    	for (Int j = 1;(1 << j) <= n;++ j)
    		for (Int i = 1;i <= n;++ i)
    			st[i][j] = st[st[i][j - 1]][j - 1];
    //			cout << i << " jump " << (1 << j) << ": " << st[i][j] << endl;
    }
    
    node getit2 (int u,int lca,int p){
    	int stp = 0;
    	for (Int i = 20;~i;-- i) if (st[u][i] && dep[st[u][i]] > dep[lca]) stp += (1 << i),u = st[u][i];
    	return node{dis[u] - dis[lca],stp};
    }
    
    int solveit (int x,int y,int P){
    	if (x == y) return 0;
    	int lca = getlca (x,y);
    	node t1 = P <= siz ? getit2 (x,lca,P) : getit1 (x,lca,P);
    	node t2 = P <= siz ? getit2 (y,lca,P) : getit1 (y,lca,P);
    	int now = t1.stp + t2.stp;
    	if (t1.lft + t2.lft <= P) return now + 1;
    	else return now + 2;
    }
    
    int ans[MAXN];
    signed main(){
    //	freopen ("data.in","r",stdin);
    //	freopen ("f1.out","w",stdout);
    	read (n),siz = sqrt (n);
    	for (Int i = 2,u,v,w;i <= n;++ i) read (u,v,w),g[u].push_back (edge{v,w}),g[v].push_back (edge{u,w});
    	dfs (1,0),read (m);
    	for (Int i = 1;i <= m;++ i) read (seq[i].u,seq[i].v,seq[i].P),seq[i].ind = i;
    	sort (seq + 1,seq + m + 1);
    	for (Int i = 1;i <= m;++ i){
    		if (seq[i].P <= siz){
    			if (seq[i].P != seq[i - 1].P) makeit (seq[i].P);
    			ans[seq[i].ind] = solveit (seq[i].u,seq[i].v,seq[i].P);
    		}
    		else ans[seq[i].ind] = solveit (seq[i].u,seq[i].v,seq[i].P);
    	}
    	for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    组织过程资产
    事业环境因素
    一起来学习Android自定义控件2-简单的写字板控件
    Android自定义控件1
    一起来学习Android自定义控件1
    Java你可能不知道的事(3)HashMap
    Java你可能不知道的事(3)HashMap
    Java你可能不知道的事(3)HashMap
    java你可能不知道的事(2)--堆和栈
    java你可能不知道的事(2)--堆和栈
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/15134778.html
Copyright © 2011-2022 走看看