zoukankan      html  css  js  c++  java
  • 【NOI2014】购票(斜率优化dp+树链剖分)

    http://uoj.ac/problem/7

    (dis[i])为到根的距离。

    dp就是:
    (f[i]=min(f[j]+(dis[i]-dis[j])*p[i]+q[i]))

    可行的(j)(i)到一个祖先的一条链。

    考虑树是一条链的时候,直接扫过去并用线段树维护下凸壳,查询就线段树上每个区间二分即可。

    树上时我用了树链剖分,即把到根路径分成(log)段连续重链。

    暴力就是线段树维护凸壳,时间复杂度:(O(n~log^3~n))

    除了最上面的那段,都是一段重链的前缀,那么在dp时,先走轻儿子,再走重儿子,维护当前这条重链的前缀的凸壳,即可一个(log)查询。

    最上面那条还是要线段树查询,时间复杂度:(O(n~log^2~n))

    凸壳用vector存,封装好加入和查询的操作,挺好写的。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 2e5 + 5;
    
    int n, tp;
    
    int fa[N]; ll fv[N], s[N], p[N], q[N], l[N];
    
    vector<int> e[N];
    #define pb push_back
    #define si size()
    
    int siz[N], son[N], w[N], top[N];
    
    void dg(int x) {
    	s[x] = s[fa[x]] + fv[x];
    	siz[x] = 1;
    	ff(_y, 0, e[x].si) {
    		int y = e[x][_y];
    		dg(y);
    		siz[x] += siz[y];
    		if(siz[y] > siz[son[x]]) son[x] = y;
    	}
    }
    
    int ed[N];
    
    void dfs(int x) {
    	if(!top[x]) top[x] = x;
    	ed[top[x]] = x;
    	w[x] = top[x] == x ? 1 : w[fa[x]] + 1;
    	if(son[x]) top[son[x]] = top[x], dfs(son[x]);
    	ff(_y, 0, e[x].si) {
    		int y = e[x][_y]; if(y == son[x]) continue;
    		dfs(y);
    	}
    }
    
    #define db double
    struct P {
    	ll x, y;
    	P(ll _x = 0, ll _y = 0) {
    		x = _x, y = _y;
    	}
    };
    db jd(P a, P b) {
    	return (db) (a.y - b.y) / (b.x - a.x);
    }
    ll dot(P a, ll x) {
    	return a.x * x + a.y;
    }
    int cmp(P a, P b) { return a.x < b.x;}
    void add(vector<P> &a, P b) {
    	while(a.si > 1 && jd(a[a.si - 2], a[a.si - 1]) <= jd(a[a.si - 1], b)) a.resize(a.si - 1);
    	a.pb(b);
    }
    ll qry(vector<P> &a, ll x) {
    	ll ans = 1e18;
    	if(a.si == 0) return 1e18;
    	int sz = a.si;
    	int as = sz - 1;
    	for(int l = 0, r = sz - 2; l <= r; ) {
    		int m = l + r >> 1;
    		if(jd(a[m], a[m + 1]) <= x) as = m, r = m - 1; else l = m + 1;
    	}
    	return dot(a[as], x);
    }
    
    int rt[N], tt;
    int pl, pr;
    ll px, py;
    
    namespace tr {
    	#define i0 t[i].l
    	#define i1 t[i].r
    	struct tree {
    		int l, r;
    	} t[N * 4];
    	vector<P> a[N * 4];
    	void add(int &i, int x, int y) {
    		if(y < pl || x > pr) return;
    		if(!i) i = ++ tt;
    		add(a[i], P(px, py));
    		if(x == y) return;
    		int m = x + y >> 1;
    		add(i0, x, m); add(i1, m + 1, y);
    	}
    	void ft(int &i, int x, int y) {
    		if(y < pl || x > pr || !i) return;
    		if(x >= pl && y <= pr) {
    			px = min(px, qry(a[i], py));
    			return;
    		}
    		int m = x + y >> 1;
    		ft(i0, x, m); ft(i1, m + 1, y);
    	}
    }
    
    ll f[N];
    
    int z[N], z0;
    
    int ef(ll L) {
    	int as = z0 - 1;
    	for(int l = 1, r = z0 - 1; l <= r; ) {
    		int m = l + r >> 1;
    		if(s[z[z0]] - s[z[m]] <= L) as = m, r = m - 1; else l = m + 1;
    	}
    	return z[as];
    }
    
    vector<P> b[N];
    
    void work(int t, int x, int y) {
    	while(top[x] != top[y]) {
    		f[t] = min(f[t], qry(b[top[x]], -p[t]));
    		x = fa[top[x]];
    	}
    	pl = w[y], pr = w[x]; px = 1e18; py = -p[t];
    	int z = top[x];
    	tr :: ft(rt[z], 1, w[ed[z]]);
    	f[t] = min(f[t], px);
    }
    
    void du(int x) {
    	z[++ z0] = x;
    	
    	if(x != 1) {
    		int z = ef(l[x]);
    		f[x] = 1e18;
    		work(x, fa[x], z);
    		f[x] += q[x] + s[x] * p[x];
    	}
    	
    	add(b[top[x]], P(s[x], f[x]));
    	pl = pr = w[x]; px = s[x]; py = f[x];
    	tr :: add(rt[top[x]], 1, w[ed[top[x]]]);
    	
    	ff(_y, 0, e[x].si) {
    		int y = e[x][_y]; if(y == son[x]) continue;
    		du(y);
    	}
    	if(son[x]) du(son[x]);
    	
    	z0 --;
    }
    
    int main() {
    	scanf("%d %d", &n, &tp);
    	fo(i, 2, n) {
    		scanf("%d %lld %lld %lld %lld", &fa[i], &fv[i], &p[i], &q[i], &l[i]);
    		e[fa[i]].pb(i);
    	}
    	dg(1); dfs(1);
    	du(1);
    	fo(i, 2, n) pp("%lld
    ", f[i]); hh;
    }
    
  • 相关阅读:
    Web Application Penetration Testing Local File Inclusion (LFI) Testing Techniques
    [Reproduced works]MongoDB Unauthorized Access Vulnerability
    PHP build notes
    两个坑-Linux下Network-Manager有线未托管-DNS resolv.conf文件开机被清空
    OS命令注入中的空格
    Honeywords项目——检查密码是否被破解的一种简单方法
    如何判断自己的VPS是那种虚拟技术实现的
    reGeorg v1.0内网流量转发
    配置OWASP的ModSecurity规则
    python 2.6 与 2.4 区别
  • 原文地址:https://www.cnblogs.com/coldchair/p/12809125.html
Copyright © 2011-2022 走看看