• BZOJ4515: [Sdoi2016]游戏


    Time Limit: 40 Sec Memory Limit: 256 MB
    Submit: 869 Solved: 336
    [Submit][Status][Discuss]

    Description

    Alice 和 Bob 在玩一个游戏。
    游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
    有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,
    若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
    他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
    Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。

    Input

    第一行两个数字 n、m,表示树的点数和进行的操作数。
    接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
    接下来 m 行。每行第一个数字是 1 或 2。
    若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
    若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。

    Output

    每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字

    Sample Input

    3 5

    1 2 10

    2 3 20

    2 1 3

    1 2 3 5 6

    2 2 3

    1 2 3 -5 -6

    2 2 3

    Sample Output

    123456789123456789

    6

    -106

    HINT

    n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9

    Source

    鸣谢Menci上传

    题解

    傻逼数据结构题
    这种题又不会做又挂细节
    还不如打暴力

    细(仔)致(细)分(观)析(摩)一(题)下(解),发现:
    每个操作“1”给路径上的点带来的数是一个关于到根的路径和的一次函数
    求最小值
    所以可以用树剖 + 超哥线段树维护

    挂各种细节,见代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    template <class T>
    inline T max(T a, T b){return a > b ? a : b;}
    template <class T>
    inline T min(T a, T b){return a < b ? a : b;}
    inline void swap(long long &x, long long &y){long long tmp = x;x = y;y = tmp;}
    inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}
    inline void read(long long &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    inline void read(int &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    const long long INF = 123456789123456789;
    const int MAXN = 100000 + 10;
    int n, q;
    struct Edge
    {
    	int v, nxt;
    	long long w;
    	Edge(int _v, long long _w, int _nxt){v = _v, w = _w, nxt = _nxt;}
    	Edge(){}
    }edge[MAXN << 1];
    int head[MAXN], cnt, deep[MAXN], tid[MAXN], tim, rank[MAXN], son[MAXN], size[MAXN], fa[MAXN], top[MAXN];
    long long sum[MAXN];
    inline void insert(int a, int b, long long c)
    {
    	edge[++ cnt] = Edge(b, c, head[a]), head[a] = cnt;
    	edge[++ cnt] = Edge(a, c, head[b]), head[b] = cnt;
    }
    void dfs1(int x)
    {
    	size[x] = 1;
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(v == fa[x]) continue; 
    		deep[v] = deep[x] + 1, sum[v] = sum[x] + edge[pos].w, fa[v] = x, dfs1(v), size[x] += size[v];
    		if(son[x] == -1 || size[son[x]] < size[v]) son[x] = v;
    	}
    }
    void dfs2(int x, int tp)
    {
    	top[x] = tp, tid[x] = ++ tim, rank[tim] = x;
    	if(son[x] != -1) dfs2(son[x], tp);
    	for(int pos = head[x];pos;pos = edge[pos].nxt)
    	{
    		int v = edge[pos].v;
    		if(v == fa[x] || v == son[x]) continue;
    		dfs2(v, v);
    	} 
    }
    int LCA(int va, int vb)
    {
    	for(;top[va] != top[vb];deep[top[va]] < deep[top[vb]] ? vb = fa[top[vb]] : va = fa[top[va]]); 
    	return deep[va] < deep[vb] ? va : vb;
    }
    struct Line
    {
    	long long k, b;
    	Line(long long _k, long long _b){k = _k, b = _b;}
    	Line(){k = b = 0;}	
    	long long f(long long x)
    	{
    		return k * x + b;
    	}
    };
    struct Node
    {
    	int l, r, tag;
    	long long mi;
    	Line line;
    }node[MAXN << 2];
    inline void pushup(int o)
    {
    	//注意:还要跟自己比较,因为标记永久化,标记可能比子节点优 
    	node[o].mi = min(node[o].mi, min(node[o << 1].mi, node[o << 1 | 1].mi));
    }
    void build(int o = 1, int l = 1, int r = tim)
    {
    	node[o].l = l, node[o].r = r, node[o].mi = INF, node[o].tag = 0;
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	build(o << 1, l, mid);
    	build(o << 1 | 1, mid + 1, r);
    }
    void modify(int ll, int rr, Line L, int o = 1)
    {
    	if(ll <= node[o].l && rr >= node[o].r)
    	{
    		long long l = sum[rank[node[o].l]], r = sum[rank[node[o].r]];
    		node[o].mi = min(node[o].mi, min(L.f(l), L.f(r)));
    		if(!node[o].tag || 
    		(node[o].tag 
    		&& node[o].line.f(l) > L.f(l) && node[o].line.f(r) > L.f(r))) 
    		{
    			node[o].line = L, node[o].tag = 1;
    			return;
    		}
    		if(node[o].line.f(l) <= L.f(l) && node[o].line.f(r) <= L.f(r)) return;
    		long long mid = (l + r) >> 1;
    		long long x = (L.b - node[o].line.b) / (node[o].line.k - L.k);
    		if(x < mid)
    		{
    			//注意:留下L,下放的是节点里的线段,脑残写错了 
    			if(node[o].line.f(r) <= L.f(r)) modify(ll, rr, L, o << 1);
    			else modify(ll, rr, node[o].line, o << 1), node[o].line = L, node[o].tag = 1;
    		}
    		else
    		{
    			if(node[o].line.f(l) <= L.f(l)) modify(ll, rr, L, o << 1 | 1);
    			else modify(ll, rr, node[o].line, o << 1 | 1), node[o].line = L, node[o].tag = 1;
    		}
    		return;
    	}
    	int mid = (node[o].l + node[o].r) >> 1;
    	if(mid >= ll) modify(ll, rr, L, o << 1);
    	if(mid < rr) modify(ll, rr, L, o << 1 | 1);
    	pushup(o);
    }
    long long ask(int ll, int rr, int o = 1)
    {
    	if(ll <= node[o].l && rr >= node[o].r) return node[o].mi;
    	int mid = (node[o].l + node[o].r) >> 1;
    	long long mi = INF;
    	if(node[o].tag) mi = min(mi, min(node[o].line.f(sum[rank[max(node[o].l, ll)]]), node[o].line.f(sum[rank[min(rr, node[o].r)]])));
    	//注意:到了o这个点说明o这个电上的线段上有[ll,rr]的一部分,所以ll要跟node[o].l取max,rr跟node[o].r取min才是o点在[ll,rr]上的部分 
    	if(mid >= ll) mi = min(mi, ask(ll, rr, o << 1));
    	if(mid < rr) mi = min(mi, ask(ll, rr, o << 1 | 1));
    	return mi;
    }
    void change_chain(int s, int t, Line L)
    {
    	int f1 = top[s], f2 = top[t];
    	while(f1 != f2)
    	{
    		if(deep[f1] < deep[f2]) swap(f1, f2), swap(s, t);
    		modify(tid[f1], tid[s], L);
    		s = fa[f1], f1 = top[s];
    	}
    	if(deep[s] > deep[t]) swap(s, t);
    	modify(tid[s], tid[t],L);
    }
    void change(int s, int t, long long a, long long b)
    {
    	int lca = LCA(s, t);
    	if(lca == s) change_chain(s, t, Line(a, -a* sum[s] + b));/*注意:链上情况单独分析,同一条链不同st是不同的*/
    	else if(lca == t) change_chain(t, s, Line(-a, a * sum[s] + b));
    	else change_chain(lca, s, Line(-a, a * sum[s] + b)), change_chain(lca, t, Line(a, a * sum[s] - a * 2 * sum[lca] + b));
    }
    long long query(int u, int v)
    {
    	int f1 = top[u], f2 = top[v];
    	long long re = INF;
    	while(f1 != f2)
    	{
    		if(deep[f1] < deep[f2]) swap(f1, f2), swap(u, v);
    		re = min(re, ask(tid[f1], tid[u]));
    		u = fa[f1], f1 = top[u];
    	}
    	if(deep[u] > deep[v]) swap(u, v);
    	re = min(re, ask(tid[u], tid[v]));
    	return re;
    }
    int tmp1, tmp2, tmp3, tmp4, tmp5;
    int main()
    {
    	freopen("data.txt", "r", stdin);
    	freopen("out.txt", "w", stdout);
    	memset(son, -1, sizeof(son));
    	read(n), read(q);
    	for(int i = 1;i < n;++ i)
    	{
    		read(tmp1), read(tmp2), read(tmp3);
    		insert(tmp1, tmp2, tmp3);
    	}
    	dfs1(1), dfs2(1, 1);build();
    	for(int i = 1; i <= q;++ i)
    	{
    		read(tmp1), read(tmp2), read(tmp3);
    		if(tmp1 == 1) read(tmp4), read(tmp5), change(tmp2, tmp3, tmp4, tmp5);
    		else printf("%lld
    ", query(tmp2, tmp3));
    	}
        return 0;
    }
    
  • 相关阅读:
    5个最佳WordPress通知栏插件
    最新lombok插件和IDEA2020.1不兼容,Plugin "Lombok" is incompatible (until build 193.SNAPSHOT < IU-201.6668....
    nuxt中localstorage的替代方案
    nuxt或者vue,axios中如何发送多个请求
    wordpress nginx详细环境配置安装命令和相关问题解决
    [no_perms] Private mode enable, only admin can publish this module
    vue bootstrap中modal对话框不显示遮挡打不开
    vue监听当前页面的地址变化/路由变化
    来看看JDK13的81个新特性和API
    Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test java.lang.IllegalStateException
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8582624.html
Copyright © 2020-2023  润新知