[CF526G]Spiders Evil Plan
题目大意:
给出一个$n(n\leq 10^5)$个结点的带边权的树,$q(q\leq 10^5)$个询问,每次询问用$y$条路径覆盖整棵树且覆盖$x$至少一次,最多能覆盖的道路长度是多少?
强制在线。
思路:
考虑固定$x$时的情况,我们可以使用长链剖分,然后贪心地选择$2y$条长链,每$2$条可以组成一条路径,这样就找出了$y$条路径的最优方案,均摊复杂度$O(n)$。
现在考虑$x$不固定的情况,对于每个询问分别做一次长链剖分,复杂度是$O(nq)$的,显然会超时。
考虑如何只用一次树剖解决所有的询问。
问题也就变成了如何确定一个根,使得所有询问的覆盖方案中,每条路径都会经过这个根。
显然,经过一点最长的路径肯定会经过直径的一个端点。
因此我们可以将直径的任一端点作为根结点开始树剖,然后贪心地选$2y-1$条最长链(最长的一条本身就是一条路径),这样时间复杂度就是$O(n+q)$。
但是这样并不是完全正确的,因为$2y-1$条最长链不一定能涵盖$x$。
因此我们需要将其中一条替换成一条经过$x$的链。
具体分为以下三种情况:
1.直接把最短的一整条链去掉;
2.把从根结点出发的一条链去掉上面一半;
3.把离$x$最近的一条链去掉下面$y$一半。
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=;
struct Edge {
int to,w;
};
bool vis[N];
std::queue<int> q;
std::vector<Edge> e[N];
int dis[N],far[N],par[N],top[N],son[N],leaf[N],rank[N],sum[N],root;
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].push_back((Edge){v,w});
e[v].push_back((Edge){u,w});
}
inline void bfs() {
q.push(root=);
vis[]=true;
while(!q.empty()) {
const int x=q.front();
q.pop();
if(dis[x]>dis[root]) root=x;
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i].to,&w=e[x][i].w;
if(vis[y]) continue;
dis[y]=dis[x]+w;
vis[y]=true;
q.push(y);
}
}
dis[root]=;
}
void dfs1(const int &x,const int &par) {
son[x]=;
::par[x]=par;
far[x]=dis[x];
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i].to,&w=e[x][i].w;
if(y==par) continue;
dis[y]=dis[x]+w;
dfs1(y,x);
if(far[y]>far[x]) {
far[x]=far[y];
son[x]=y;
}
}
}
void dfs2(const int &x) {
if(x==son[par[x]]) {
top[x]=top[par[x]];
} else {
top[x]=x;
}
if(son[x]) {
dfs2(son[x]);
} else {
leaf[++leaf[]]=x;
}
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i].to;
if(y==par[x]||y==son[x]) continue;
dfs2(y);
}
}
inline bool cmp(const int &x,const int &y) {
return dis[x]-dis[par[top[x]]]>dis[y]-dis[par[top[y]]];
}
inline int query(const int &x,const int &y) {
if(rank[top[x]]<=y*-) {
return sum[std::min(y*-,leaf[])];
}
int u=x;
while(rank[top[u]]>y*-) {
u=par[top[u]];
}
return sum[y*-]-std::min(std::min(sum[y*-]-sum[y*-],far[u]-dis[u]),dis[u])+(far[x]-dis[u]);
}
int main() {
const int n=getint(),q=getint();
for(register int i=;i<n;i++) {
const int u=getint(),v=getint(),w=getint();
add_edge(u,v,w);
}
bfs();
dfs1(root,);
dfs2(root);
std::sort(&leaf[],&leaf[+leaf[]],cmp);
for(register int i=;i<=leaf[];i++) {
rank[top[leaf[i]]]=i;
sum[i]=sum[i-]+dis[leaf[i]]-dis[par[top[leaf[i]]]];
}
for(register int i=,ans=;i<q;i++) {
const int x=(getint()+ans-)%n+,y=(getint()+ans-)%n+;
printf("%d\n",ans=query(x,y));
}
return ;
}
[CF526G]Spiders Evil Plan的更多相关文章
- 【CF526G】Spiders Evil Plan(贪心)
[CF526G]Spiders Evil Plan(贪心) 题面 洛谷 CodeForces 给定一棵树,要求选择\(y\)条链,满足被链覆盖的所有点在树上联通,且\(x\)必定在联通块中. 对于每次 ...
- CF Contest 526 G. Spiders Evil Plan 长链剖分维护贪心
LINK:Spiders Evil Plan 非常巧妙的题目. 选出k条边使得这k条边的路径覆盖x且覆盖的边的边权和最大. 类似于桥那道题还是选择2k个点 覆盖x那么以x为根做长链剖分即可. 不过这样 ...
- Codeforces 526G Spiders Evil Plan
由于做的时候看的是中文题面,第一遍写就被卡题意了:还以为每一条都要过x,那么就是一道动态树根选择2y个叶子的奇怪题目 交完0分gg,才发现题目看错了╮(╯▽╰)╭ the node containin ...
- Codeforces 526G - Spiders Evil Plan(长链剖分+直径+找性质)
Codeforces 题目传送门 & 洛谷题目传送门 %%%%% 这题也太神了吧 storz 57072 %%%%% 首先容易注意到我们选择的这 \(y\) 条路径的端点一定是叶子节点,否则我 ...
- code forces 383 Arpa's loud Owf and Mehrdad's evil plan(有向图最小环)
Arpa's loud Owf and Mehrdad's evil plan time limit per test 1 second memory limit per test 256 megab ...
- Arpa's loud Owf and Mehrdad's evil plan
Arpa's loud Owf and Mehrdad's evil plan time limit per test 1 second memory limit per test 256 megab ...
- Codeforces Round #383 (Div. 2)C. Arpa's loud Owf and Mehrdad's evil plan
C. Arpa's loud Owf and Mehrdad's evil plan time limit per test 1 second memory limit per test 256 me ...
- Codeforces Round #383 (Div. 2) C. Arpa's loud Owf and Mehrdad's evil plan —— DFS找环
题目链接:http://codeforces.com/contest/742/problem/C C. Arpa's loud Owf and Mehrdad's evil plan time lim ...
- 【codeforces 742C】Arpa's loud Owf and Mehrdad's evil plan
time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...
随机推荐
- Dev express 笔记
1.设置treelist不同行的颜色 void treeList1_CustomDrawNodeCell(object sender, DevExpress.XtraTreeList.CustomDr ...
- UVA1316 Supermarket
题目描述 有一个商店有许多批货,每一批货又有N(0<=N<= 10^4104 )个商品,同时每一样商品都有收益 P_iPi ,和过期时间 D_iDi (1<= Pi,DiPi,D ...
- NAT64与DNS64基本原理概述
NAT64与DNS64基本原理概述 1.NAT64与DNS64背景 在IPv6网络的发展过程中,面临最大的问题应该是IPv6与IPv4的不兼容性,因此无法实现二种不兼容网络之间的互访.为了实现 ...
- Linux下从零开始部署和使用Jaeger
最近在折腾Jaeger,Jaeger官网都是介绍如何通过Docker部署,二进制部署文档基本没有(已咨询过作者,作者说没文档!你参考Docker自己部署好了!!!),所以打算写一篇Linux部署. J ...
- OnCommand® Unified Manager
OnCommand Unified Manager Solution Components The following components are downloaded and installe ...
- 一键GHOST
软件简介: 一键GHOST是"DOS之家"首创的4种版本(硬盘版/光盘版/优盘版/软盘版)同步发布的启动盘,适应各种用户需要,既可独立使用,又能相互配合.主要功能包括:一键备份系统 ...
- python装饰器(整理版)
Python中函数有一个装饰器的概念,今天,看核心编程中的函数一章的时候接触到了这个概念,炸一看来,讲的说明真实不好明白.于是写下本篇以示说明,提供给迷糊者.希望能对一些人起到一定的帮助 装饰器的语法 ...
- cygwin设置
解决乱码问题 # 设置为中文环境,使提示成为中文 export LANG =" zh_CN.UTF-8 " # 输出为中文编码 export OUTPUT_CHARSET =& ...
- Linux下Tcpdump使用
1. 介绍 tcpdump是一款用来截取网络数据的工具:这里主要介绍的是为嵌入式Linux编译tcpdump的方法 2. 编译 首先去官网下载源代码, 需要下载tcpdump和libpcap, 将他们 ...
- linux进程地址空间--vma的基本操作【转】
转自:http://blog.csdn.net/vanbreaker/article/details/7855007 版权声明:本文为博主原创文章,未经博主允许不得转载. 在32位的系统上,线性地址空 ...