zoukankan      html  css  js  c++  java
  • 【SPOJ】1825. Free tour II(点分治)

    http://www.spoj.com/problems/FTOUR2/

    先前看了一会题解就自己yy出来了。。。对拍过后交tle。。。。。。。。。。。。。。。。。。

    自己造了下大数据。。。。。。。。tle。。。。。。。。。。。。。。。。。。。。。。。。。

    what?

    首先来看经过当前点的路径:

    设g[x,i]表示第x个孩子能得到的路径上黑点最多有i个(注意是最多)的最大长度,因为遍历的节点最坏为n个(第一层),因此在每一层都是$O(n)$的,可以承受。

    考虑转移答案

    $$ans[x]=max{g[u,i]+g[v,k-black[x]-i], u!=v}$$

    这个方程似乎很显然?如果看不懂的请仔细思考所定义的状态,特别是“最多为i个”

    可是最坏情况下有$n$个黑点,所以状态数目就有$n^2$了(尽管在每一层中有效转移状态仅仅为$O(n)$),而且暴力转移也是$O(n^2)$

    考虑减少状态,试着去掉第一维。发现如果有序遍历每个子女时,之前遍历过的可以直接查找,而且每一次都是同样的操作(即查找之前子女的每一个状态),而转移是max,想到合并为一个状态。那么状态只剩$O(n)$

    但是发现,如果k达到了$n$,那么我们在更新g值的话(更新g值就是从小的黑点更新大的黑点,即g[i]=max{g[j], j<=i},会tle成狗。。。。因为每次都要更新到k。。。。)

    就是到这里我交了tle。。。。。。。。。。。。。。。。。。然后想不出来了。。。。。。。。。。。。。。。。。

    做法:发现如果子女遍历黑点的深度是递增的话,因为每次更新g值不超过当前黑点深度,所以所有更新g值次数加起来均摊$O(n)$

    排序子女深度$O(nlgn)$,因此本题总时间复杂度为$O(nlg^2n)$

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    
    const int N=200005, oo=~0u>>1;
    int ihead[N], cnt, n;
    struct dat { int next, to, w; }e[N<<1];
    inline void add(int u, int v, int w) {
    	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].w=w;
    	e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].w=w;
    }
    int root, sz[N], vis[N], ans, h[N], blc[N], g[N], bsz[N], K, mn;
    void getroot(int x, int fa, int sum) {
    	sz[x]=1; int mx=0, y;
    	rdm(x, i) if(!vis[y=e[i].to] && e[i].to!=fa) {
    		getroot(y, x, sum);
    		sz[x]+=sz[y];
    		mx=max(mx, sz[y]);
    	}
    	mx=max(mx, sum-mx);
    	if(mx<mn) mn=mx, root=x;
    }
    void cal(int x, int len, int num, int fa) {
    	h[num]=max(h[num], len); int y;
    	rdm(x, i) if(!vis[y=e[i].to] && e[i].to!=fa) {
    		cal(y, len+e[i].w, num+blc[y], x);
    	}
    }
    void fix(int len) {
    	int mx=-oo;
    	for1(i, 0, len) {
    		mx=max(mx, g[i]);
    		g[i]=mx;
    	}
    }
    void getbsz(int x, int fa) {
    	bsz[x]=blc[x];
    	rdm(x, i) if(!vis[e[i].to] && e[i].to!=fa) getbsz(e[i].to, x), bsz[x]+=bsz[e[i].to];
    }
    struct QQ {
    	int dep, id;
    	bool operator<(const QQ &a) const { return dep<a.dep; }
    }q[N];
    void dfs(int x, int sum) {
    	vis[x]=1;
    	int y, maxdep=-1, kk=K-blc[x];
    	int tot=0, pos;
    	rdm(x, i) if(!vis[y=e[i].to]) {
    		getbsz(y, x);
    		q[++tot].dep=bsz[y];
    		q[tot].id=i;
    	}
    	sort(q+1, q+1+tot);
    	for1(i, 1, tot) {
    		int now=q[i].id, y=e[now].to, s=min(q[i].dep, kk);
    		for1(j, 0, s) h[j]=-oo;
    		cal(y, e[now].w, blc[y], x);
    		if(i==1) for1(j, 0, s) g[j]=h[j];
    		else {
    			for1(j, 0, s) {
    				pos=kk-j; if(pos>maxdep) pos=maxdep;
    				if(g[pos]!=-oo && h[j]!=-oo) ans=max(g[pos]+h[j], ans);
    			}
    			for1(j, 0, s) g[j]=max(g[j], h[j]);
    		}
    		maxdep=s;
    		fix(maxdep);
    	}
    	ans=max(ans, g[min(kk, maxdep)]);
    	rdm(x, i) if(!vis[y=e[i].to]) {
    		int s=sz[y]>sz[x]?sum-sz[x]:sz[y];
    		root=0; mn=oo; getroot(y, x, s);
    		dfs(root, s);
    	}
    }
    int main() {
    	read(n); read(K); int m=getint();
    	for1(i, 1, m) blc[getint()]=1;
    	rep(i, n-1) { int u=getint(), v=getint(), w=getint(); add(u, v, w); }
    	mn=oo;
    	getroot((n+1)>>1, -1, n);
    	dfs(root, n);
    	print(ans);
    	return 0;
    }
    

      


    After the success of 2nd anniversary (take a look at problem FTOUR for more details), this 3rd year, Travel Agent SPOJ goes on with another discount tour.

    The tour will be held on ICPC island, a miraculous one on the Pacific Ocean. We list N places (indexed from 1 to N) where the visitors can have a trip. Each road connecting them has an interest value, and this value can be negative (if there is nothing interesting to view there). Simply, these N places along with the roads connecting them form a tree structure. We will choose two places as the departure and destination of the tour.

    Since September is the festival season of local inhabitants, some places are extremely crowded (we call them crowded places). Therefore, the organizer of the excursion hopes the tour will visit at most K crowded places (too tiring to visit many of them) and of course, the total number of interesting value should be maximum.

    Briefly, you are given a map of N places, an integer K, and M id numbers of crowded place. Please help us to find the optimal tour. Note that we can visit each place only once (or our customers easily feel bored), also the departure and destination places don't need to be different.

    Input

    There is exactly one case. First one line, containing 3 integers N K M, with 1 <= N <= 200000, 0 <=K <= M, 0 <= M <= N.

    Next M lines, each line includes an id number of a crowded place.

    The last (N - 1) lines describe (N - 1) two-way roads connected N places, form a b i, with a, b is the id of 2 places, and i is its interest value (-10000 <= i <= 10000).

    Output

    Only one number, the maximum total interest value we can obtain.

    Example

    Input:
    8 2 3
    3
    5
    7
    1 3 1
    2 3 10
    3 4 -2
    4 5 -1
    5 7 6
    5 6 5
    4 8 3
    
    
    Output:
    12
    

    Explanation

    We choose 2 and 6 as the departure and destination place, so the tour will be 2 -> 3 -> 4 -> 5 -> 6, total interest value = 10 + (-2) + (-1) + 5 = 12
  • 相关阅读:
    第01组 Alpha冲刺 总结
    第01组 Alpha冲刺 (6/6)
    小黄衫买家秀及获奖感言
    软工实践个人总结
    实验 7:OpenDaylight 实验——Python 中的 REST API 调用
    实验 6:OpenDaylight 实验——OpenDaylight 及 Postman 实现流表下发
    实验 5:OpenFlow 协议分析和 OpenDaylight 安装
    SDN实验 4:Open vSwitch 实验——Mininet 中使用 OVS 命令
    实验 3:Mininet 实验——测量路径的损耗率
    2020软件工程个人编程作业一:统计分析GitHub 的用户行为数据
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4172993.html
Copyright © 2011-2022 走看看