[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 ...
随机推荐
- 孤荷凌寒自学python第二十六天python的time模块的相关方法
孤荷凌寒自学python第二十六天python的time模块的相关方法 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 要使用time模块的相关方法,必须在文件顶端引用: import tim ...
- [转]Shell dev-null详解
转自: https://blog.csdn.net/wenwenxiong/article/details/46882733 1,可以将/dev/null看作"黑洞". 它非常等价 ...
- intellij idea 2017 快捷键(提高工作效率)
1.Shift+Enter Annotation annotation = c.getAnnotation(A.class); 这个时候你写代码的时候可能光标在c.getAnno中的某一个位置,那么你 ...
- hdu 1534 Schedule Problem (差分约束)
Schedule Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 论文笔记《Hand Gesture Recognition with 3D Convolutional Neural Networks》
一.概述 Nvidia提出的一种基于3DCNN的动态手势识别的方法,主要亮点是提出了一个novel的data augmentation的方法,以及LRN和HRn两个CNN网络结合的方式. 3D的CNN ...
- Codeforces Round #352 (Div. 2) B
B. Different is Good time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- ie8 不支持media
可以用respond.js库解决,bootstrap文件夹里有.同时需要注意以下几点. 1.需要启动本地服务器(localhost),不能使用普通本地的url地址(file://开头): 2.需要外部 ...
- Codevs 2080 特殊的质数肋骨
题目描述 Description 农民约翰的母牛总是产生最好的肋骨. 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们. 农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋 ...
- 求LCA最近公共祖先的在线ST算法_C++
ST算法是求最近公共祖先的一种 在线 算法,基于RMQ算法,本代码用双链树存树 预处理的时间复杂度是 O(nlog2n) 查询时间是 O(1) 的 另附上离线算法 Tarjan 的链接: http ...
- 【调试】js调试console.log使用总结图解(重要)
0.介绍 先上图:不知道有多少人发现,在浏览器开发工具的“Console”上的百度首页的关于百度招聘的信息: 今天要给大家介绍的就是是Web前端调试工具中的Console面板,应该说只要是个浏览器就会 ...