题目大意:
  给出一个$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的更多相关文章

  1. 【CF526G】Spiders Evil Plan(贪心)

    [CF526G]Spiders Evil Plan(贪心) 题面 洛谷 CodeForces 给定一棵树,要求选择\(y\)条链,满足被链覆盖的所有点在树上联通,且\(x\)必定在联通块中. 对于每次 ...

  2. CF Contest 526 G. Spiders Evil Plan 长链剖分维护贪心

    LINK:Spiders Evil Plan 非常巧妙的题目. 选出k条边使得这k条边的路径覆盖x且覆盖的边的边权和最大. 类似于桥那道题还是选择2k个点 覆盖x那么以x为根做长链剖分即可. 不过这样 ...

  3. Codeforces 526G Spiders Evil Plan

    由于做的时候看的是中文题面,第一遍写就被卡题意了:还以为每一条都要过x,那么就是一道动态树根选择2y个叶子的奇怪题目 交完0分gg,才发现题目看错了╮(╯▽╰)╭ the node containin ...

  4. Codeforces 526G - Spiders Evil Plan(长链剖分+直径+找性质)

    Codeforces 题目传送门 & 洛谷题目传送门 %%%%% 这题也太神了吧 storz 57072 %%%%% 首先容易注意到我们选择的这 \(y\) 条路径的端点一定是叶子节点,否则我 ...

  5. 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 ...

  6. 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 ...

  7. 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 ...

  8. 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 ...

  9. 【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 ...

随机推荐

  1. Oracle 学习----:查看当前时间与Sqlserver语句不一样了

    oracle:select sysdate from dual sqlserver: select getdate() ---------------------试试这个--------------- ...

  2. 孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库

    孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第三天.感觉这个东西学习起来还是那么困 ...

  3. React01

    目录 React-day01 入门知识 React介绍 官网 React开发环境初始化 SPA 脚手架初始化项目(方便,稳定)* 通过webpack进行初始化 配置镜像地址 开发工具配置 元素渲染 组 ...

  4. Python课程设计 搭建博客

    安装包Github地址 Python综合设计 233博客 注意还有个email文件是需要填入自己信息的,比如最高权限账号和要发送邮件的账号密码 请安装Python2.7环境,本服务器所用环境为 设置环 ...

  5. ocrosoft Contest1316 - 信奥编程之路~~~~~第三关 问题 x: 十进制到二进制的转换

    http://acm.ocrosoft.com/problem.php?cid=1316&pid=49 题目描述 把十进制到二进制的转换. 输入 234 输出 11101010 样例输入 23 ...

  6. hdu 2899 Strange fuction (二分法)

    Strange fuction Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  7. Dom的深度优先遍历和广度优先遍历

    //深度优先遍历的递归写法 function DFTraversal(node) { var nodes = []; if (node != null) { nodes.push(node); var ...

  8. swipe display: none后再显示,加载内容后,滑动失效问题

    只需要添加这两个属性即可: observer:true,//修改swiper自己或子元素时,自动初始化swiper observeParents:true//修改swiper的父元素时,自动初始化sw ...

  9. 如何用js让表格的行也能拖动

    行拖动的实现思路非常简单,选中一行,往上拖就与上面的行交换位置,往下拖就与下面的行交换位置.问题是如何得到交换行.我见过一个非常详细的教程,它会把表格里的每一行的高度与Y坐标计算出来,换言之,都时是比 ...

  10. ACM童年生活二三事

    描述 Redraiment小时候走路喜欢蹦蹦跳跳,他最喜欢在楼梯上跳来跳去. 但年幼的他一次只能走上一阶或者一下子蹦上两阶. 现在一共有N阶台阶,请你计算一下Redraiment从第0阶到第N阶共有几 ...