zoukankan      html  css  js  c++  java
  • [2010国家集训队]Crash的旅游计划

    Description

    眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游。
    Crash和陶陶所要去的城市里有N (N > 1) 个景点,Crash用正整数1到N给景点标号。
    这些景点之间通过N - 1条无向道路相连,每条道路有一个长度,并且保证任意两个景点之间都有且仅有一条路径相连。
    现在对于一个景点s,Crash和陶陶从s出发,然后访问一个景点序列{v0, v1, v2, … , vk},
    其中v0就是s,且vi-1和vi(0 < i ≤ k)之间有道路相连。
    需要注意的是,陶陶和Crash访问的景点序列中不会只有景点s。
    为了使旅程不显得乏味,在一个景点序列里他们不会重复走某条道路。
    我们定义这个序列的旅游代价为经过道路的长度和。下面问题出现了:
    陶陶:我们走一条景点数最多的景点序列吧。
    Crash:倒,你想把我累死啊。
    陶陶:谁叫你整天坐在电脑前面,不出来锻炼,这下子傻了吧,哈哈哈哈~~
    Crash:不行,如果你非要走景点数最多的我就不陪你走了。
    陶陶:笑喷油你很跳嘛!
    Crash:这样吧,我们来写伸展树,如果我写的比你快,你就要听我的。
    陶陶:这样不公平哎,我们来玩PES吧,当然你要让我选法国队,如果你输了你就要听我的。
    Crash:倒,你这是欺负我,T_T~
    陶陶:笑喷油好说话哎。
    Crash:囧……
    ……
    这样搞了半天,最终陶陶和Crash用很多次包剪锤决定出选择旅游代价第K小 的景点序列。
    不过呢Crash和陶陶还没确定开始旅行的景点s,因此他希望你对于每个景点i,计算从景点i开始的景点序列中旅游代价第K小的值。

    Input

    共N行。
    第1行包含一个字符和两个正整数,字符为ABCD中的一个,用来表示这个测试数据的类型
    (详见下面的数据规模和约定),另外两个正整数分别表示N和K (K < N),N<=100000
    第2行至第N行,每行有三个正整数u、v和w (u, v ≤ N,w ≤ 10000)。
    表示u号景点和v号景点之间有一条道路,长度为w。
    输入文件保证符合题目的约定,即任意两个景点之间都有且仅有一条路径相连。

    Output

    共N行,每行有一个正整数。
    第i行的正整数表示从i号景点开始的景点序列中旅游代价第K小的代价。

    Sample Input

    A 6 3

    1 2 2

    1 3 4

    1 4 3

    3 5 1

    3 6 2

    Sample Output

    4

    6

    4

    7

    5

    6

    //样例1中输出对应的景点序列分别为:

    1号景点是{1, 3},2号景点是{2, 1, 3},3号景点是{3, 1},4号景点是{4, 1, 3},5号景点是{5, 3, 1},6号景点是{6, 3, 1}。

    保证每个景点到1号景点需要经过的道路数不超过30


    题解

    题意就是给出(n)个点的一棵树,对于每个点求出距离ta第(k)小的距离

    动态点分治
    我们可以先建出点分树
    然后二分一个距离(k),判断其他点到这个点的距离小于等于这个值的有几个
    那么现在的问题就是给出一个点,求出到这个点的距离不大于(k)的有几个点
    (v1[u])数组表示(u)的子树内的点到(u)的距离,(v2[u])表示(u)的子树内的点到(fa[u])的距离
    然后每次查询点(u)的时候就顺着点分树往上跳,期间查询所有的点到点(u)的距离不超过(k)的点
    注意每次往上跳到(fa[u])再查(fa[u])的子树的时候会把已经统计过的(u)的子树的信息重复统计一部分,所以我们要容斥掉(u)的子树内的信息
    注意往上跳的时候如果跳到点(x)使得(dis(u,x)>k)也不要直接(break),而是要继续往上跳,因为点分树是将原树重构了,可能(dis(u,x)>k)了但是(x)的祖先到(u)的距离(le k)

    代码

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 200005 ;
    const int INF = 1e9 ;
    using namespace std ;
    
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    bool vis[M] ;
    int n , k , num , tot , tmx , root , hea[M] ; 
    int dis[M] , ff[M] , fa[M] , size[M] , dep[M] , son[M] , top[M] ;
    vector < int > v1[M] , v2[M] ;
    struct E { int nxt , to , dis ; } edge[M * 2] ;
    inline void add_edge(int from , int to , int dis) {
    	edge[++num].nxt = hea[from] ; edge[num].to = to ;
    	edge[num].dis = dis ; hea[from] = num ;
    }
    
    void dfs1(int u , int father , int depth) {
    	ff[u] = father ; size[u] = 1 ; dep[u] = depth ; int mx = -1 ;
    	for(int i = hea[u] ; i ; i = edge[i].nxt) {
    		int v = edge[i].to ; if(v == father) continue ;
    		dis[v] = dis[u] + edge[i].dis ; dfs1(v , u , depth + 1) ; 
    		size[u] += size[v] ;  if(size[v] > mx) mx = size[v] , son[u] = v ;
    	}
    }
    void dfs2(int u , int topf) {
    	top[u] = topf ; if(!son[u]) return ; dfs2(son[u] , topf) ;
    	for(int i = hea[u] ; i ; i = edge[i].nxt) {
    		int v = edge[i].to ; if(v == ff[u] || v == son[u]) continue ;
    		dfs2(v , v) ;
    	}
    }
    inline int LCA(int x , int y) {
    	while(top[x] != top[y]) {
    		if(dep[top[x]] < dep[top[y]]) swap(x , y) ;
    		x = ff[top[x]] ;
    	}
    	return dep[x] < dep[y] ? x : y ;
    }
    inline int Gdis(int x , int y) {
    	return dis[x] + dis[y] - dis[LCA(x , y)] * 2 ;
    }
    void findroot(int u , int father) {
    	size[u] = 1 ; int mx = 0 ;
    	for(int i = hea[u] ; i ; i = edge[i].nxt) {
    		int v = edge[i].to ; if(vis[v] || v == father) continue ;
    		findroot(v , u) ; mx = max(mx , size[v]) ; size[u] += size[v] ;
    	}
    	mx = max(mx , tot - size[u]) ;
    	if(mx < tmx) tmx = mx , root = u ;
    }
    
    void Solve(int u , int father) {
    	fa[u] = father ; vis[u] = true ;
    	for(int i = hea[u] ; i ; i = edge[i].nxt) {
    		int v = edge[i].to ; if(vis[v]) continue ;
    		tot = size[v] ; tmx = INF ; 
    		findroot(v , u) ; Solve(root , u) ;
    	}
    }
    // v1 表示u的子树内的点到u的距离
    // v2 表示u的子树内的点到fa[u]的距离 
    inline void Insert(int x) {
    	v1[x].push_back(0) ;
    	for(int u = x ; fa[u] ; u = fa[u]) {
    		v1[fa[u]].push_back(Gdis(x , fa[u])) ;
    		v2[u].push_back(Gdis(x , fa[u])) ;
    	}
    }
    inline int query(int id , int x , int k) {
    	if(id == 1) {
    		int l = 0 , r = v1[x].size() - 1 , mid , ret = -1 ;
    		while(l <= r) {
    			mid = (l + r) >> 1 ;
    			if(v1[x][mid] <= k) l = mid + 1 , ret = mid ;
    			else r = mid - 1 ;
    		}
    		return ret + 1 ;
    	}
    	else {
    		int l = 0 , r = v2[x].size() - 1 , mid , ret = -1 ;
    		while(l <= r) {
    			mid = (l + r) >> 1 ;
    			if(v2[x][mid] <= k) l = mid + 1 , ret = mid ;
    			else r = mid - 1 ;
    		}
    		return ret + 1 ;
    	}
    }
    inline int check(int x , int k) {
    	int ans = query(1 , x , k) ;
    	for(int u = x , dis1 ; fa[u] ; u = fa[u]) {
    		dis1 = Gdis(x , fa[u]) ; if(k - dis1 < 0) continue ;
    		ans += query(1 , fa[u] , k - dis1) - query(2 , u , k - dis1) ;
    	}
    	return ans - 1 ;
    }
    int main() {
    	char s[10] ; scanf("%s",s) ; n = read() ; k = read() ;
    	for(int i = 1 , u , v , w ; i < n ; i ++) {
    		u = read() ; v = read() ; w = read() ;
    		add_edge(u , v , w) ; add_edge(v , u , w) ;
    	}
    	dfs1(1 , 0 , 1) ; dfs2(1 , 1) ; 
    	tot = n ; tmx = INF ; findroot(1 , 0) ; Solve(root , 0) ;
    	for(int i = 1 ; i <= n ; i ++) Insert(i) ;
    	for(int i = 1 ; i <= n ; i ++) {
    		sort(v1[i].begin() , v1[i].end()) ;
    		sort(v2[i].begin() , v2[i].end()) ;
    	}
    	for(int u = 1 ; u <= n ; u ++) {
    		int l = 1 , r = 1e9 , ret = 0 ;
    		while(l <= r) {
    			int mid = (l + r) >> 1 ;
    			if(check(u , mid) >= k) ret = mid , r = mid - 1 ;
    			else l = mid + 1 ;
    		}
    		printf("%d
    ",ret) ;
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    深度学习优化方法比较
    调参
    Numpy/Pytorch之数据类型与强制转换
    numpy:维度问题
    js模板引擎-juicer
    js模板引擎-腾讯artTemplate 简洁语法例子
    canva绘制时钟
    js中的break ,continue, return
    JavaScript奇技淫巧44招
    数据类型
  • 原文地址:https://www.cnblogs.com/beretty/p/10645671.html
Copyright © 2011-2022 走看看