• P4069 [SDOI2016]游戏 [李超树,树链剖分]


    考虑到某个连续的段一定是离根的长度增加于是随便搞就行了,有点难调。

    // by Isaunoya
    #include<bits/stdc++.h>
    #define rep(i, x, y) for(int i = x; i <= y; ++i)
    #define Rep(i, x, y) for(int i = x; i >= y; --i)
    #define int long long
    using namespace std;
    struct io {
    	char buf[1 << 27 | 3], *s;
    	int f;
    	io() { f = 0, buf[fread(s = buf, 1, 1 << 27, stdin)] = '
    '; }
    	io& operator >> (int&x) {
    		for(x = f = 0; !isdigit(*s); ++s) f |= *s  == '-';
    		while(isdigit(*s)) x = x * 10 + (*s++ ^ 48);
    		return x = f ? -x : x, *this;
    	}
    };
    struct io_out {
    	char buf[1 << 27 | 3], *s = buf;
    	~io_out() { fwrite(buf, 1, s - buf, stdout); }
    	void write(int x) { if(x > 9) write(x / 10); *s++ = x % 10 ^ '0'; }
    	io_out& operator << (int x) {
    		if(x < 0) x = -x, *s++ = '-';
    		write(x); return *this;
    	}
    	io_out& operator << (char x) { *s++ = x; return *this; }
    } out;
    int n;
    const int maxn = 4e5 + 54;
    struct Edge {
    	int v, nxt, w;
    } e[maxn << 1];
    int head[maxn], cnt = 0;
    void add(int u, int v, int w) {
    	e[++ cnt] = { v, head[u], w }, head[u] = cnt;
    	e[++ cnt] = { u, head[v], w }, head[v] = cnt;
    }
    const int inf = 123456789123456789ll;
    struct Line {
    	int k, b;
    	Line(int _k = 0, int _b = inf) { k = _k, b = _b; }
    	int val(int x) { return k * x + b; }
    } a[maxn << 1];
    int fa[maxn], sz[maxn], dep[maxn], len[maxn], f[maxn][22], son[maxn];
    void dfs(int u) {
    	sz[u] = 1, dep[u] = dep[fa[u]] + 1;
    	for(int i = head[u], v = e[i].v; i; v = e[i = e[i].nxt].v) 
    		if(v != fa[u]) { fa[v] = u, len[v] = len[u] + e[i].w; dfs(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; }
    }
    int lca(int x, int y) {
    	if(dep[x] < dep[y]) swap(x, y);
    	for(int i = 20; ~i; --i) if(dep[f[x][i]] >= dep[y]) x = f[x][i]; if(x == y) return x;
    	for(int i = 20; ~i; --i) if(f[x][i] ^ f[y][i]) { x = f[x][i], y = f[y][i]; }
    	return f[x][0];
    }
    int top[maxn], idx = 0, dfn[maxn], rev[maxn];
    void dfs(int u, int t) {
    	top[u] = t, dfn[u] = ++idx; rev[dfn[u]] = u; if(son[u]) dfs(son[u], t);
    	for(int i = head[u], v = e[i].v; i; v = e[i = e[i].nxt].v) if(!top[v]) dfs(v, v);
    }
    struct LCT {
    	LCT() {}
    	int id[maxn << 2], mn[maxn << 2];
    	void up(int p) { mn[p] = min({mn[p], mn[p << 1], mn[p << 1 | 1]}); }
    	void build(int l, int r, int p) {
    		mn[p] = inf; id[p] = 0; if(l == r) { return ; }
    		int mid = l + r >> 1; build(l, mid, p << 1), build(mid + 1, r, p << 1 | 1); up(p);
    	}
    	void upd(int ql, int qr, int l, int r, int p, int x) {
    		int mid = l + r >> 1;
    		if(ql <= l && r <= qr) {
    			int &y = id[p]; 
    			int lx = a[x].val(len[rev[l]]), ly = a[y].val(len[rev[l]]);
    			int rx = a[x].val(len[rev[r]]), ry = a[y].val(len[rev[r]]);
    			if(lx <= ly && rx <= ry) { y = x; mn[p] = min({mn[p], lx, rx}); return; }
    			if(lx >= ly && rx >= ry) { return; }
    			int midx = a[x].val(len[rev[mid]]), midy = a[y].val(len[rev[mid]]);
    			if(midx <= midy) swap(x, y), swap(midx, midy), swap(lx, ly), swap(rx, ry);
    			if(lx <= ly) upd(ql, qr, l, mid, p << 1, x);
    			else upd(ql, qr, mid + 1, r, p << 1 | 1, x);
    			mn[p] = min({mn[p], lx, rx, ly, ry}), up(p); return;
    		}
    		if(ql <= mid) upd(ql, qr, l, mid, p << 1, x);
    		if(qr > mid) upd(ql, qr, mid + 1, r, p << 1 | 1, x);
    		up(p);
    	}
    	int qry(int ql, int qr, int l, int r, int p) {
    		if(ql <= l && r <= qr) { return mn[p]; }
    		int mid = l + r >> 1, ans = inf;
    		if(a[id[p]].b != inf) ans = min({ans, a[id[p]].val(len[rev[max(l, ql)]]), a[id[p]].val(len[rev[min(r, qr)]])});
    		if(ql <= mid) ans = min(ans, qry(ql, qr, l, mid, p << 1));
    		if(qr > mid) ans = min(ans, qry(ql, qr, mid + 1, r, p << 1 | 1)); 
    		return ans;
    	}
    } smt;
    int tot = 0;
    void upd(int x, int y) {
    	while(top[x] != top[y]) { smt.upd(dfn[top[x]], dfn[x], 1, n, 1, tot), x = fa[top[x]]; }
    	smt.upd(dfn[y], dfn[x], 1, n, 1, tot);
    }
    void mdf(int s, int t, int k, int b) {
    	int Lca = lca(s, t); a[++ tot] = Line(-k, k * len[s] + b); upd(s, Lca);
    	a[++ tot] = Line(k, k * (len[s] - (len[Lca] << 1)) + b); upd(t, Lca);
    }
    int qry(int x, int y) {
    	int ans = inf;
    	while(top[x] != top[y]) {
    		if(dep[top[x]] < dep[top[y]]) swap(x, y);
    		ans = min(ans, smt.qry(dfn[top[x]], dfn[x], 1, n, 1)); x = fa[top[x]];
    	}
    	if(dep[x] > dep[y]) swap(x, y); ans = min(ans, smt.qry(dfn[x],dfn[y], 1, n, 1));
    	return ans;
    }
    signed main() {
    #ifdef LOCAL
    	freopen("testdata.in", "r", stdin);
    #endif
    	io in;
    	in >> n; int _; in >> _;
    	rep(i, 2, n) { int x, y, z; in >> x >> y >> z, add(x, y, z); }
    	dfs(1), dfs(1, 1); rep(i, 1, n) f[i][0] = fa[i]; rep(j, 1, 20) rep(i, 1, n) f[i][j] = f[f[i][j - 1]][j - 1];
    	smt.build(1, n, 1);
    	while(_ --) {
    		int op, s, t, a, b;
    		in >> op >> s >> t; if(op == 1) in >> a >> b;
    		if(op == 1) { mdf(s, t, a, b); } else { out << qry(s, t) << '
    '; }
    	}
    	return 0;
    }
    
  • 相关阅读:
    【转】如何高效地阅读技术类书籍与博客
    测试站点大全
    【转】软件测试面试- 购物车功能测试用例设计
    div+css 定位浅析
    C# Enum,Int,String的互相转换
    sqlserver 空间数据类型
    系统学习sqlserver2012 一
    sql查询数据库中所有表的记录条数,以及占用磁盘空间大小。
    linux网站推荐
    匿名用户访问sharepoint2010中的列表
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12838829.html
Copyright © 2020-2023  润新知