[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 ...
随机推荐
- Oracle 学习----:查看当前时间与Sqlserver语句不一样了
oracle:select sysdate from dual sqlserver: select getdate() ---------------------试试这个--------------- ...
- 孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库
孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第三天.感觉这个东西学习起来还是那么困 ...
- React01
目录 React-day01 入门知识 React介绍 官网 React开发环境初始化 SPA 脚手架初始化项目(方便,稳定)* 通过webpack进行初始化 配置镜像地址 开发工具配置 元素渲染 组 ...
- Python课程设计 搭建博客
安装包Github地址 Python综合设计 233博客 注意还有个email文件是需要填入自己信息的,比如最高权限账号和要发送邮件的账号密码 请安装Python2.7环境,本服务器所用环境为 设置环 ...
- ocrosoft Contest1316 - 信奥编程之路~~~~~第三关 问题 x: 十进制到二进制的转换
http://acm.ocrosoft.com/problem.php?cid=1316&pid=49 题目描述 把十进制到二进制的转换. 输入 234 输出 11101010 样例输入 23 ...
- hdu 2899 Strange fuction (二分法)
Strange fuction Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- Dom的深度优先遍历和广度优先遍历
//深度优先遍历的递归写法 function DFTraversal(node) { var nodes = []; if (node != null) { nodes.push(node); var ...
- swipe display: none后再显示,加载内容后,滑动失效问题
只需要添加这两个属性即可: observer:true,//修改swiper自己或子元素时,自动初始化swiper observeParents:true//修改swiper的父元素时,自动初始化sw ...
- 如何用js让表格的行也能拖动
行拖动的实现思路非常简单,选中一行,往上拖就与上面的行交换位置,往下拖就与下面的行交换位置.问题是如何得到交换行.我见过一个非常详细的教程,它会把表格里的每一行的高度与Y坐标计算出来,换言之,都时是比 ...
- ACM童年生活二三事
描述 Redraiment小时候走路喜欢蹦蹦跳跳,他最喜欢在楼梯上跳来跳去. 但年幼的他一次只能走上一阶或者一下子蹦上两阶. 现在一共有N阶台阶,请你计算一下Redraiment从第0阶到第N阶共有几 ...