板子题 Sol
Cyber_Tree 出了一道板子题。。。
这题乍看之下貌似还不戳,但如果您做过类似的题,那么这就是一道板子题。。。。
首先明确要求的是什么,如果我们只考虑权值最大而不考虑最小距离,那么要求的显然就是森林中每棵基环树的最长链,即直径。。。
如果您已经知道了怎么求,那么可以直接关闭该题解了。。。。。
考虑如何求一棵基环树的直径。
发现如果直径上包含环上的边会很难求,因此可以分类讨论,分别求得不包含环上的边的最长链和包含环上的最长链即可。。。
首先考虑不包含链上的点的情况,显然可以忽略所有环上的边,然后用一个简单的树形 \(dp\) 解决。与此同时还可以求得对于环上的每一个点 \(u\) ,仅经过非环边与其距离最远的点距离是多少,记为 \(f_{u}\)。
接下来考虑若包含链上的边该怎么求,显然对于环上任意两个点 \(u, v\) ,显然经过这两个的最长链长度为 \(f_{u}+f_{v}+dis_{u, v}\) ,如果直接枚举每个点对显然是 \(O(n^{2})\) 的,因此考虑优化。
环上的问题不难想到破环为链,破环为链后两个点的距离可以用前缀和表示,则原式可以被表示为 \(f_{u}+f_{v}+sum_{u}-sum_{v}\) ,这个式子显然可以用单调队列进行优化,每次将 \(f_{u}-sum_{u}\) 插入队列即可。
以上,为基环树的直径求法。。。
然而此题还包含的一个最小距离,该怎么处理呢?
直接将 \(f\) 数组改成一个二元组,重载运算符后进行相同操作即可。
如果没有做过基环树直径的题,可以拿来练手,题中有亿些细节需要注意。。。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define t first
#define w second
const int N=1e6+10;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, deg[N], to[N], q1[N], stk[N<<1], top;
struct node{
ll x, y;
friend node operator + (const node &a, const node &b) { return (node){a.x+b.x, a.y+b.y}; }
friend node operator - (const node &a, const node &b) { return (node){a.x-b.x, a.y-b.y}; }
friend bool operator < (const node &a, const node &b) { return a.x==b.x ? a.y > b.y : a.x < b.x; }
friend bool operator <= (const node &a, const node &b) { return a.x==b.x ? a.y >= b.y : a.x < b.x; }
friend bool operator == (const node &a, const node &b) { return a.x==b.x&&a.y==b.y; }
}wr[N];
node sum[N<<1];
node f[N], maxn, ans;
vector<pair<int, node> > l[N];
queue<int> q;
bool cir[N], vis[N], in[N];
inline void topsort(){
for(int i=1; i<=n; ++i) if(deg[i]==1) q.push(i), cir[i]=1;
while(!q.empty()){
int u=q.front(); q.pop();
for(pair<int, node> v : l[u])
if(!cir[v.t]&&(--deg[v.t])==1) q.push(v.t), cir[v.t]=1;
}
}
void pre_dfs(int u, int fa){
vis[u]=1;
for(pair<int, node> v : l[u]){
if(!cir[v.t]&&v.t!=fa&&!in[v.t]&&!cir[u]) stk[++top]=v.t, sum[top]=v.w, in[v.t]=1;
if(vis[v.t]) continue;
pre_dfs(v.t, u);
}
}
void dfs1(int u, int fa){
f[u]=(node){0, 0};
for(pair<int, node> v : l[u]){
if(v.t==fa||!cir[v.t]) continue;
dfs1(v.t, u);
maxn=max(maxn, f[u]+v.w+f[v.t]);
f[u]=max(f[u], f[v.t]+v.w);
}
maxn=max(maxn, f[u]);
}
signed main(void){
freopen("naive.in", "r", stdin);
freopen("naive.out", "w", stdout);
n=read();
for(int i=1; i<=n; ++i) to[i]=read(), wr[i]=(node){read(), read()};
for(int i=1; i<=n; ++i){
if(to[to[i]]==i&&(wr[i]<wr[to[i]]||(wr[i]==wr[to[i]]&&to[i]<i))) continue;
l[i].push_back(make_pair(to[i], wr[i]));
l[to[i]].push_back(make_pair(i, wr[i]));
++deg[to[i]]; ++deg[i];
}
topsort();
for(int i=1; i<=n; ++i){
if(vis[i]) continue;
top=0; pre_dfs(i, 0); node tmp=(node){0, 0}; maxn=(node){0, 0};
if(!top){
dfs1(i, 0); tmp=maxn; maxn=(node){0, 0};
ans=ans+tmp; continue;
}
for(int j=1; j<=top; ++j)
dfs1(stk[j], 0), tmp=max(maxn, tmp), maxn=(node){0, 0};
for(int j=1; j<=top; ++j) stk[j+top]=stk[j], sum[j+top]=sum[j];
for(int j=1; j<=top<<1; ++j) sum[j]=sum[j]+sum[j-1];
int l=1, r=0;
for(int j=1; j<=top<<1; ++j){
while(j-q1[l]>=top&&l<=r) ++l;
if(l<=r) tmp=max(tmp, f[stk[j]]+f[stk[q1[l]]]+sum[j]-sum[q1[l]]);
while(f[stk[q1[r]]]-sum[q1[r]]<=f[stk[j]]-sum[j]&&l<=r) --r;
q1[++r]=j;
}
ans=ans+tmp;
}
printf("%lld %lld\n", ans.x, ans.y);
return 0;
}
板子题 Sol的更多相关文章
- POJ 1321 棋盘问题(DFS板子题,简单搜索练习)
棋盘问题 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44012 Accepted: 21375 Descriptio ...
- POJ 3278 Catch That Cow(BFS,板子题)
Catch That Cow Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 88732 Accepted: 27795 ...
- Gym 100952J&&2015 HIAST Collegiate Programming Contest J. Polygons Intersection【计算几何求解两个凸多边形的相交面积板子题】
J. Polygons Intersection time limit per test:2 seconds memory limit per test:64 megabytes input:stan ...
- hihoCoder #1038 : 01背包(板子题)
#1038 : 01背包 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励 ...
- [LOJ 6270]数据结构板子题
Description 有n个区间,第i个区间是[li,ri],它的长度是ri−li. 有q个询问,每个询问给定L,R,K,询问被[L,R]包含的且长度不小于K的区间数量. 你想,像这种板子题,你随手 ...
- 堆以及一些用法 QWQ这是写得最认真的板子题
最近一直在学图论,然后吧,由于学的东西实在是太多太杂了,加上蒟蒻本蒻又经常颓,所以落了好多好多板子题的整理没写啊嘤嘤嘤,不过把这些东西学的差不多了,再一块写个整理,其实感觉还不错?????也算是很神奇 ...
- bzoj-1787-洛谷-4281(LCA板子题)
传送门(bzoj) 传送门(洛谷) 可以说这道也是一个板子题 由于题中是三个人需经过的路径最短 就会有一点点不太一样 那么 就两两求LCA 这样之后就会出现两种状况 一.所得到的三个LCA是相等的 那 ...
- bzoj3944: Sum 杜教筛板子题
板子题(卡常) 也可能是用map太慢了 /************************************************************** Problem: 3944 Us ...
- AC自动机板子题/AC自动机学习笔记!
想知道484每个萌新oier在最初知道AC自动机的时候都会理解为自动AC稽什么的,,,反正我记得我当初刚知道这个东西的时候,我以为是什么神仙东西,,,(好趴虽然确实是个对菜菜灵巧比较难理解的神仙知识点 ...
随机推荐
- php获取当前用户ip
function wcs_get_onlineip() { $onlineip = ''; if(getenv('HTTP_CLIENT_IP') && strcasecmp(gete ...
- 🔥 LeetCode 热题 HOT 100(41-50)
102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...
- 比@EnableMongoAuditing功能强大的实现
问题出现 以前通过@EnableMongoAuditing.@CreateDate.@LastModifiedDate进行实体类创建时间.修改时间的自动管理. 但为了实现多数据源的管理以及切换,自己覆 ...
- [JS]异步任务之事件循环
前言 常常会听到单线程和多线程这两个名词,单线程即一个时间段内程序从上到下执行任务,多线程即一个时间段内程序同时执行多个任务. 然而 JavaScript 是单线程的,它不像 Java 那样新开启一个 ...
- noip模拟33[进阶啦啦啦]
noip模拟33 solutions 不知道该咋说,这场考试其实是我这三四场以来最最最最最顺心的一场了 为啥呢?因为我这回思考有很多结果,得到了脑袋的回复 就是你想了半个小时就有了一点点头绪,那感觉就 ...
- 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件 内容简介:本文介绍 Spring Boot 的配置文件和配置管理,以及介绍了三种读取配置文 ...
- netty系列之:中国加油
目录 简介 场景规划 启动Server 启动客户端 消息处理 消息处理中的陷阱 总结 简介 之前的系列文章中我们学到了netty的基本结构和工作原理,各位小伙伴一定按捺不住心中的喜悦,想要开始手写代码 ...
- 干了六年Android开发现在裸辞失业了,再过2个月就30了,该怎么继续生活?
这是我在某论坛看到别人分享的故事,觉得可以展开聊一下,对于我们这些中年程序员,可以裸辞吗? 前言 首先介绍一下主人公的情况.目前所在的是一家小的创业公司,待了3年多,薪资一般吧,之前在一家中型上市企业 ...
- [数据结构-平衡树]普通 FHQ_Treap从入门到精通(注释比代码多系列)
普通 FHQ_Treap从入门到精通(注释比代码多系列) 前提说明,作者写注释太累了,文章里的部分讲解来源于Oi-wiki,并根据代码,有部分增改.本文仅仅发布于博客园,其他地方出现本文,均是未经许可 ...
- MySQL-06-DQL语句
DQL sql文件下载链接: https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/world.sql selec ...