[UOJ 87] #87. mx的仙人掌

#87. mx的仙人掌

UOJ 87

题目大意

给出一个 \(n\) 个点,\(m\) 条边的带边权的仙人掌,定义两点之间距离为最短路长度,\(Q\) 次询问,每次给出 \(cnt\) 个点,问它们之间最远点对的距离。

数据范围

边权不超过 \(2^{31} - 1\)

\(n, \sum cnt \le 300000\)

时空限制

5s, 512MB

分析

此题如果不是仙人掌,那就是每次建出虚树来 DP

仙人掌求最短路也就是建出圆方树后根据 \(lca\) 分类讨论,那么,我们就根据圆方树建一个虚树,如果当前节点是圆点那么就和树的情况 ,如果当前节点为方点那么它的儿子提出来,在环上用单调队列更新答案即可

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
inline char nc() {
    return getchar();
    static char buf[100000], *l = buf, *r = buf;
    return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T & x) {
    x = 0; int f = 1, ch = nc();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=nc();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10-‘0‘+ch;ch=nc();}
    x *= f;
}
typedef long long ll;
const int maxn = 300000 + 5;
const int maxm = maxn * 2;
const int maxe = maxm * 2;
const int maxnode = maxn * 2;
const int maxlog = 20;
const int sigma_cnt = 300000 + 5;
int n, m, Q, cnt, p[sigma_cnt]; ll an;
int sta[sigma_cnt], que[sigma_cnt << 1];
ll f[maxnode];
int head[maxnode], ecnt;
int dfc, dfn[maxnode], low[maxn], anc[maxn]; ll dist[maxn];
int dep[maxnode], parent[maxnode][maxlog]; ll dis[maxnode];
int bcnt; ll sum[maxn];
map<int, int> E[maxn];
vector<int> adj[maxnode];
struct edge {
    int to, nex; ll cost;
    edge(int to=0, int nex=0, ll cost=0) : to(to), nex(nex), cost(cost) {}
} g[maxe];
inline void addedge1(int u, int v, int w) {
    if(E[u].count(v)) E[u][v] = min(E[u][v], w); else E[u][v] = w;
    if(E[v].count(u)) E[v][u] = min(E[v][u], w); else E[v][u] = w;
}
inline void addedge2(int u, int v, ll w) {
    g[ecnt] = edge(v, head[u], w), head[u] = ecnt++;
    g[ecnt] = edge(u, head[v], w), head[v] = ecnt++;
}
inline void addedge3(int u, int v) {
    adj[u].push_back(v);
}
void tarjan(int u) {
    low[u] = dfn[u] = ++dfc;
    for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
        int v = it->first;
        if(!dfn[v]) {
            dist[v] = dist[u] + it->second;
            anc[v] = u; tarjan(v);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u]) {
                addedge2(u, v, it->second);
            }
        }
        else if(anc[u] != v) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
        int v = it->first;
        if(anc[v] != u && dfn[v] >= dfn[u]) {
            int now = ++bcnt; sum[now] = dist[v] - dist[u] + it->second;
            for(int x = v; ; x = anc[x]) {
                ll t = dist[x] - dist[u]; addedge2(now + n, x, min(t, sum[now] - t));
                if(x == u) break;
            }
        }
    }
}
void dfs(int u) {
    dfn[u] = ++dfc;
    for(int i = 1; i < maxlog; ++i) {
        parent[u][i] = parent[ parent[u][i - 1] ][i - 1];
    }
    for(int i = head[u]; ~ i; i = g[i].nex) {
        int v = g[i].to; if(v == parent[u][0]) continue;
        dep[v] = dep[u] + 1, dis[v] = dis[u] + g[i].cost;
        parent[v][0] = u; dfs(v);
    }
}
void jump(int & u, int k) {
    for(int i = maxlog - 1; ~ i; --i) {
        if(k >= (1 << i)) {
            k -= 1 << i;
            u = parent[u][i];
        }
    }
}
int lca(int u, int v) {
    if(dep[u] > dep[v]) swap(u, v);
    jump(v, dep[v] - dep[u]);
    if(u == v) return u;
    for(int i = maxlog - 1; ~ i; --i) {
        if(parent[u][i] != parent[v][i]) {
            u = parent[u][i];
            v = parent[v][i];
        }
    }
    return parent[u][0];
}
void update(int u, int n) {
    static ll f[sigma_cnt << 1], g[sigma_cnt << 1];
    for(int i = 1; i <= n; ++i) {
        f[i] = dist[ sta[i] ], f[n + i] = f[i] + sum[u - ::n];
        g[i] = ::f[ sta[i] ], g[n + i] = g[i];
    }
    n <<= 1; int l = 0, r = -1;
    for(int i = 1; i <= n; ++i) {
        while(l <= r && (f[i] - f[ que[l] ]) * 2 > sum[u - ::n]) l++;
        if(l <= r) an = max(an, g[ que[l] ] - f[ que[l] ] + g[i] + f[i]);
        while(l <= r && g[ que[r] ] - f[ que[r] ] <=  g[i] - f[i]) r--;
        que[++r] = i;
    }
}
void dp(int u) {
    f[u] = 0; int top = 0;
    for(unsigned int i = 0; i < adj[u].size(); ++i) {
        int v = adj[u][i]; dp(v);
    }
    for(unsigned int i = 0; i < adj[u].size(); ++i) {
        int v = adj[u][i];
        if(u <= n) an = max(an, f[u] + f[v] + dis[v] - dis[u]);
        else {
            int s = v; jump(s, dep[v] - dep[u] - 1);
            f[s] = f[v] + dis[v] - dis[s]; sta[++top] = s;
        }
        f[u] = max(f[u], f[v] + dis[v] - dis[u]);

    }
    if(u > n) update(u, top);
    adj[u].clear();
}
int cmp(const int & a, const int & b) {
    return dfn[a] < dfn[b];
}
void solve() {
    read(cnt);
    for(int i = 1; i <= cnt; ++i) read(p[i]);
    sort(p + 1, p + cnt + 1, cmp), cnt = unique(p + 1, p + cnt + 1) - p - 1;
    int top = 0; sta[++top] = p[1];
    for(int i = 2; i <= cnt; ++i) {
        int w = lca(sta[top], p[i]);
        while(top > 1 && dep[ sta[top - 1] ] > dep[w]) {
            addedge3(sta[top - 1], sta[top]); top--;
        }
        if(dep[sta[top]] > dep[w]) addedge3(w, sta[top--]);
        if(w != sta[top]) sta[++top] = w;
        sta[++top] = p[i];
    }
    while(top > 1) {
        addedge3(sta[top - 1], sta[top]); top--;
    }
    an = 0; dp(sta[top]); printf("%lld\n", an);
}
int main() {
    read(n), read(m);
    for(int i = 1; i <= m; ++i) {
        int u, v, w;
        read(u), read(v), read(w);
        addedge1(u, v, w);
    }
    memset(head, -1, sizeof(head)); tarjan(1);
    for(int i = 1; i <= n; ++i) E[i].clear();
    dfc = 0; dfs(1);
    read(Q);
    for(int i = 1; i <= Q; ++i) solve();
    return 0;
}

原文地址:https://www.cnblogs.com/ljzalc1022/p/10241991.html

时间: 2024-10-29 18:10:25

[UOJ 87] #87. mx的仙人掌的相关文章

uoj#87. mx的仙人掌

1 //Achen 2 #include<bits/stdc++.h> 3 #define For(i,a,b) for(int i=(a);i<=(b);i++) 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 5 #define Formylove return 0 6 const int N=2e6+7,mod=571111; 7 typedef long long LL; 8 typedef double db; 9 using

Notes : &lt;Hands-on ML with Sklearn &amp; TF&gt; Chapter 7

.caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px solid #000; } .table { border-collapse: collapse !important; } .table td, .table th { background-color: #fff !important; } .table-bordered th, .table-bordere

第13章 使用Bind提供域名解析服务

章节简述: 本章节将让您理解DNS服务程序的原理,学习正向解析与反向解析实验,掌握DNS主服务器.从服务器.缓存服务器的部署方法. 够熟练配置区域信息文件与区域数据文件,以及通过使用分离解析技术让不同来源的用户得到更合适的解析结果. DNS服务作为互联网的基础设施,我们还可以配置BIND服务程序支持TSIG安全加密传输机制,从而保障解析数据不被嗅探监听. 本章目录结构 13.1 了解域名解析服务 13.2 安装Bind服务程序 13.3 DNS服务的解析实验 13.3.1 正向解析实验 13.3

切忧欺涝搪o5st80t820z99

霍雨浩赶忙追上去拉住王冬,"你怎么了王冬?"就连他刚才也并没有感觉到王冬在情绪上的不对,这种突如其来的变化他也有些不知所措的感觉正像其他人认为的那样,霍雨浩也并不觉得王冬会有问题,之前他也从未听王冬说过对魂导器有这么强烈的排斥更何况还是在之前王言老师讲述了那么多真实情况的前下毒不死怒视玄老,托天双掌猛然在空中作出一个下砸的动作.顿时,就在玄老头顶上方,一颗直径超过三十米的巨大绿色光球仿佛是从虚空中钻出来似的悍然出现.直奔玄老当头砸下.三个人,一个团队.他们最终获得了新生考核决赛的冠军.

Hnoi2017试题泛做

Day1 4825: [Hnoi2017]单旋 注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序. 所以我们可以离线地把这棵树的中序遍历求出来.然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态. 接着我们发现将最大.最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1.于是我们就只要支持单点修改.区间加.单点查询的数据结构即可.树状数组就好了. 然后树的形态维护的时候大力判断一下就好啦. 1 #include <cstdio> 2

授行普鬃杏ed9a4dug71g19e70dr8

"啊?"霍雨浩一呆,"你不是说让我不惜一切的争取这块魂骨么?"穆老微微一笑,道:"老夫名叫穆恩,相信在这个世界上还记得老夫名字的人已经不多了."--马小桃脸上流露出一个灿烂的笑容,却不再说话,看那样子倒是很满意的.四更完毕,筋疲力尽中求月票.推荐票.让大家提前享受了推荐榜第一的四更,有了感觉,是不是就能更给力一些了呢?快月底了,还有力气,咱们就冲一把!身为魂导师,通过远程魂导器锁定目标这是最基础的课程.更别说笑红尘这种五级魂导师了.就算伤的再重,

【UVA11478】Halum (最短路解差分约束)

题目: Sample Input2 11 2 102 11 2 -103 31 2 42 3 23 1 54 52 3 44 2 53 4 23 1 01 2 -1Sample OutputInfiniteInfinite31 题意: 给定一个有向图,每条边都有一个权值.每次你可以选择一个结点v和一个整数d,把所有以v为终点的边的权值减小d,把所有以v为起点的边的权值增加d,最后让所有边的权值的最小值大于零且尽量大. 分析: 因为不同的操作互不影响,因此可以按任意顺序实施这些操作.另外,对于同一

bzoj 3676 [Apio2014]回文串(Manacher+SAM)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题意] 给定一个字符串,定义一个串的权值为长度*出现次数,求最大权的回文子串. [思路] 马拉车求出本质不同的回文子串. 对于一个回文子串,在SAM中用倍增法在O(logn)的时间得到它的出现次数,即SAM中每个节点的right集大小,倍增数组和right都可以通过提前处理得到. 更新答案即可. [代码] 1 #include<set> 2 #include<cmat

web之三建立https

书接上文,复习一条:elinks -dump:获取到页面数据后直接退出进程.我们的keepAlive在根据需求定义不同的时长,如果繁忙,则调短一些. 如何将http使用成https ssl:secure socket layer 安全套接字层 ssv1 ssv2 ssv3 ~tls1 tls  传输层安全 因为http协议时明文的,基于文本编码. telnet 使用telnet发起请求,此时我们的服务器仍是192.168.1.126 而我们的客户端多了一个192.168.1.134了 [[ema