HDU - 5770 Treasure 思维 + 扫描线 + 线段树 (看题解)

Posted cjlhy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 5770 Treasure 思维 + 扫描线 + 线段树 (看题解)相关的知识,希望对你有一定的参考价值。

HDU - 5770

没想出来, 感觉不应该啊, 没有想到转换成二维上的点的问题。

对于对钥匙和宝藏(u, v), 如果lca != u && lca != v 那么起点从u子树出发, 终点在v子树就能得到贡献。

子树在dfs序下是连续一段, 所以就对应到二维平面一个矩形加上一个数值, 求值最大的点。

对于lca == u || lca == v同样可以讨论出来。 

还有一种情况就是u == v, 我们先把贡献都加上, 然后对于不经过u 的所有路径进去这个贡献。

然后扫描线扫一遍就好了。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = (int)1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) a += b; if(a >= mod) a -= mod;
template<class T, class S> inline void sub(T& a, S b) a -= b; if(a < 0) a += mod;
template<class T, class S> inline bool chkmax(T& a, S b) return a < b ? a = b, true : false;
template<class T, class S> inline bool chkmin(T& a, S b) return a > b ? a = b, true : false;

const int LOG = 17;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1

struct SegmentTree 
    int mx[N << 2], lazy[N << 2];
    void build(int l, int r, int rt) 
        mx[rt] = lazy[rt] = 0;
        if(l == r) return;
        int mid = l + r >> 1;
        build(lson); build(rson);
    
    inline void push(int rt) 
        if(lazy[rt]) 
            mx[rt << 1] += lazy[rt];
            mx[rt << 1 | 1] += lazy[rt];
            lazy[rt << 1] += lazy[rt];
            lazy[rt << 1 | 1] += lazy[rt];
            lazy[rt] = 0;
        
    
    void update(int L, int R, int val, int l, int r, int rt) 
        if(R < l || r < L || R < L) return;
        if(L <= l && r <= R) 
            mx[rt] += val;
            lazy[rt] += val;
            return;
        
        push(rt);
        int mid = l + r >> 1;
        update(L, R, val, lson);
        update(L, R, val, rson);
        mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
    
    inline int getMax() 
        return mx[1];
    
 Tree;


int n, m;
int sig_val;
int add_val[N];
int in[N], ot[N], idx;
int depth[N], pa[N][LOG];
vector<int> G[N];

void dfs(int u, int fa) 
    depth[u] = depth[fa] + 1;
    pa[u][0] = fa;
    in[u] = ++idx;
    for(int i = 1; i < LOG; i++) 
        pa[u][i] = pa[pa[u][i - 1]][i - 1];
    
    for(auto &v : G[u]) 
        if(v == fa) continue;
        dfs(v, u);
    
    ot[u] = idx;


int getLca(int u, int v) 
    if(depth[u] < depth[v]) swap(u, v);
    int d = depth[u] - depth[v];
    for(int i = LOG - 1; i >= 0; i--) 
        if(d >> i & 1) 
            u = pa[u][i];
        
    
    if(u == v) return u;
    for(int i = LOG - 1; i >= 0; i--) 
        if(pa[u][i] != pa[v][i]) 
            u = pa[u][i];
            v = pa[v][i];
        
    
    return pa[u][0];


inline int go(int u, int step) 
    for(int i = LOG - 1; i >= 0; i--) 
        if(step >> i & 1) 
            u = pa[u][i];
        
    
    return u;


int L_cnt;
struct Line 
    int x, y1, y2, val;
    bool operator < (const Line &rhs) const 
        return x < rhs.x;
    
 L[N * 10];

void init() 
    idx = L_cnt = sig_val = 0;
    for(int i = 1; i <= n; i++) 
        add_val[i] = 0;
        G[i].clear();
    
    Tree.build(1, n, 1);


int main() 
    int cas = 0;
    int T; scanf("%d", &T);
    while(T--) 
        scanf("%d%d", &n, &m);
        init();
        for(int i = 1; i < n; i++) 
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        
        dfs(1, 0);
        for(int i = 1; i <= m; i++) 
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            int lca = getLca(u, v);
            if(u == v) 
                sig_val += w;
                add_val[u] -= w;
            
            else 
                if(u == lca) 
                    u = go(v, depth[v] - depth[u] - 1);
                    if(in[u] > 1) 
                        L[++L_cnt] = Line1, in[v], ot[v], w;
                        L[++L_cnt] = Linein[u], in[v], ot[v], -w;
                    
                    if(ot[u] < n) 
                        L[++L_cnt] = Lineot[u] + 1, in[v], ot[v], w;
                        L[++L_cnt] = Linen + 1, in[v], ot[v], -w;
                    
                
                else if(v == lca) 
                    v = go(u, depth[u] - depth[v] - 1);
                    if(in[v] > 1) 
                        L[++L_cnt] = Linein[u], 1, in[v] - 1, w;
                        L[++L_cnt] = Lineot[u] + 1, 1, in[v] - 1, -w;
                    
                    if(ot[v] < n) 
                        L[++L_cnt] = Linein[u], ot[v] + 1, n, w;
                        L[++L_cnt] = Lineot[u] + 1, ot[v] + 1, n, -w;
                    
                
                else 
                    L[++L_cnt] = Linein[u], in[v], ot[v], w;
                    L[++L_cnt] = Lineot[u] + 1, in[v], ot[v], -w;
                
            
        
        for(int u = 1; u <= n; u++) 
            if(add_val[u]) 
                for(auto &v : G[u]) 
                    if(v == pa[u][0]) continue;
                    L[++L_cnt] = Linein[v], in[v], ot[v], add_val[u];
                    L[++L_cnt] = Lineot[v] + 1, in[v], ot[v], -add_val[u];
                
                if(pa[u][0]) 
                    int v = u;
                    L[++L_cnt] = Line1, 1, in[v] - 1, add_val[u];
                    L[++L_cnt] = Line1, ot[v] + 1, n, add_val[u];
                    L[++L_cnt] = Linein[v], 1, in[v] - 1, -add_val[u];
                    L[++L_cnt] = Linein[v], ot[v] + 1, n, -add_val[u];

                    L[++L_cnt] = Lineot[v] + 1, 1, in[v] - 1, add_val[u];
                    L[++L_cnt] = Lineot[v] + 1, ot[v] + 1, n, add_val[u];
                
            
        
        int ans = -inf;
        sort(L + 1, L + 1 + L_cnt);
        for(int i = 1, j = 1; i <= n; i++) 
            while(j <= L_cnt && L[j].x <= i) 
                if(L[j].y1 <= L[j].y2) 
                    Tree.update(L[j].y1, L[j].y2, L[j].val, 1, n, 1);
                
                j++;
            
            chkmax(ans, sig_val + Tree.getMax());
        
        printf("Case #%d: ", ++cas);
        printf("%d\n", ans);
    
    return 0;


/*
*/

 

以上是关于HDU - 5770 Treasure 思维 + 扫描线 + 线段树 (看题解)的主要内容,如果未能解决你的问题,请参考以下文章

cug oj 1479 Treasure Chest Lock (区间dp 思维)

HDU5446:Unknown Treasure——题解

HDU5446 Unknown Treasure(组合数+Lucas+中国剩余定理)

hdu 5446 Unknown Treasure 卢卡斯+中国剩余定理

HDU 5446 Unknown Treasure(Lucas定理+CRT)

hdu 3642 Get The Treasure