CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)

http://codeforces.com/contest/1184/problem/E2

题意:给出一副图,首先求出这幅图的最小生成树 , 然后修改这幅图上不属于最小生成树的边权,使得修改后的图在求一边生成树的时候可以包含被修改的边(注意:修改的边权要最大 )题目规定只有一课生成树

分析:

现在我们需要解决所有非树边的任务(MST保证是惟一的)。我们要求对于非树边(u, v),正确答案是u和v之间路径上的最大权值MST。(证明:≤:由MSTs的循环特性可知;≥:如果(u, v)的重量大于这个最大值,然后用(u, v)交换获得最大值的边,会得到一个更便宜的树a矛盾。

所以现在我们的任务就是求任意两点在生成树上的路径最大边权。这题我们可以用LCA的思想去完成,我们现在预处理出了一条路上走过的最大值,那么答案所求mx=max(mx(u->w) , mx(v->w)) ;w为u,v的最近公共祖先,这里采用倍增法的思想去完成

#include<bits/stdc++.h>
using namespace std ;
int n,m;
const int maxn = 1e6+3;
vector<pair<int,int> >G[maxn];
int pre[maxn],fa[maxn][19],dep[maxn],mx[maxn][19],ans[maxn];
struct no
{
    int id,u,v,w;
}a[maxn];
bool cmp(no a , no b)
{
    return a.w<b.w;
}
int ffind(int x)
{
    if(pre[x]==x) return x;
    pre[x]=ffind(pre[x]);
    return pre[x];
}
void dfs(int u , int p)
{
    for(int i=0 ; i<G[u].size() ; i++)
    {
        int v=G[u][i].first;
        if(p==v) continue;
        dep[v]=dep[u]+1;
        fa[v][0]=u;
        mx[v][0]=G[u][i].second;
        dfs(v,u);
    }
}
int lca(int u , int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0 ; i<18 ; i++)
    if((dep[v]-dep[u])&(1<<i)) v=fa[v][i];
    if(u==v) return u;
    for(int i=17 ; i>=0 ; i--)
    if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int ask(int u , int st)
{
    int ret=0;
    for(int i=0 ; i<18 ; i++)
    if(st&(1<<i)) ret=max(ret,mx[u][i]),u=fa[u][i];
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0 ; i<m ; i++)
    {
        a[i].id=i;
        scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
    }
    ///卡鲁思
    for(int i=1 ; i<=n ; i++) pre[i]=i;
    sort(a,a+m,cmp);
    for(int i=0 ; i<m ; i++)
    {
        int u=ffind(a[i].u) , v=ffind(a[i].v);
        if(u!=v)
        {
            pre[u]=v;
            ans[a[i].id]=-1;
            G[a[i].u].push_back({a[i].v,a[i].w});
            G[a[i].v].push_back({a[i].u,a[i].w});
        }
    }
    ///lca
    dep[1]=1; dfs(1,0);
    for(int i=1 ; i<18 ; i++)
    for(int j=1 ; j<=n ; j++)
    {
        fa[j][i]=fa[fa[j][i-1]][i-1];
        mx[j][i]=max(mx[j][i-1],mx[fa[j][i-1]][i-1]);
    }
    for(int i=0 ; i<m ; i++)
    if(ans[a[i].id]!=-1)
    {
        int u=a[i].u ,v=a[i].v , w=lca(u,v);
        ans[a[i].id]=max(ask(u,dep[u]-dep[w]),ask(v,dep[v]-dep[w]));
    }
    for(int i=0 ; i<m ; i++)
    {
        if(ans[i]!=-1)
        printf("%d ",ans[i]);
    }
}

CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)

原文地址:https://www.cnblogs.com/shuaihui520/p/11150481.html

时间: 2024-07-31 15:42:18

CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)的相关文章

poj 2455 Secret Milking Machine 【二分 + 最大流】 【1到N不重复路径不少于T条时,求被选中路径上的最大边权值 的最小值】

Secret Milking Machine Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10620   Accepted: 3110 Description Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within

求一个指定点对的路径上的最大边权或最小边权

dij贪心地取min(cur,pre)最大的路径 或者直接按权值排序,贪心地从最小或最大取,并茶几加点,联通停止即可... 我们还可以用二分..就是二分最大边权或者最小边权..重复上面类似kruskal的过程 k短路..次小生成树..可持久化堆 dij本质还是个贪心地过程 求满足某条件的最短路径或最长路径,如果该条件满足可以筛出的满足某性质的点中可形成的路径解集中包含题目所有的答案 我们就可以先用BFS等手段先把点筛出来..然后在这些点中跑各种路径算法 对于最短路径我们可以考察是否有负环..对于

CF 191C Fools and Roads lca 或者 树链剖分

They say that Berland has exactly two problems, fools and roads. Besides, Berland has n cities, populated by the fools and connected by the roads. All Berland roads are bidirectional. As there are many fools in Berland, between each pair of cities th

LeetCode 236. Lowest Common Ancestor of a Binary Tree(二叉树求两点LCA)

题意:二叉树求两点LCA. /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* lowestCommonAncestor(TreeNode

[cf1184E]Daleks&#39; Invasion

先求出任意一棵最小生成树,然后对边分类讨论1.非树边,答案即最小生成树的环上的最长边2.树边,反过来考虑,相当于对于每一个点对那条路经打上标记,取min对于1直接用倍增维护即可,对于2可以用树链剖分/差分+启发式合并但都需要两个log,所以有一种很神奇的做法考虑从小到大枚举非树边,然后暴力修改,容易发现修改过的边就不用修改了,因此复杂度是o(m),问题是如何快速找到没有被修改过的边,可以使用并查集将修改过的边缩起来然后快速往上爬即可 1 #include<bits/stdc++.h> 2 us

【LCA求最近公共祖先+vector构图】Distance Queries

Distance Queries 时间限制: 1 Sec  内存限制: 128 MB 题目描述 约翰的奶牛们拒绝跑他的马拉松,因为她们悠闲的生活不能承受他选择的长长的赛道.因此他决心找一条更合理的赛道.此题的输入于第一题相同,紧接着下一行输入一个整数K,以后K行为K个"距离问题".每个距离问题包括两个整数,就是约翰感兴趣的两个农场的编号,请你尽快算出这两地之间的距离. N个点,N-1条边 输入 第1行:两个分开的整数:N和M: 第2..M+1行:每行包括4个分开的内容,F1,F2,L,

蓝桥--危险系数(求两点之间的割点个数)

历届试题 危险系数 时间限制:1.0s   内存限制:256.0MB 问题描述 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个危险系数DF(x,y): 对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点.相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数. 本

PJOI PKU Campus 2011 B:A Problem about Tree LCA 求任意点x为根的y的父节点

题目链接:点击打开链接 题意:给定n个点 m个询问 下面n-1行给定一棵树 m个询问 x y 问把树转成以x为根 y的父节点是谁 第一种情况lca==y那就是x的第 dep[x] - dep[y] -1 父亲,依次向上爬山坡,利用倍增的二进制加速. 第二种就是Father[y]; #include"cstdio" #include"iostream" #include"queue" #include"algorithm" #i

UVALive - 7831 :ACM Tax (主席树求树路径上中位数:LCA+主席树)

题意:给定一棵带权树,Q次询问,每次询问路径上的中位数. 思路:中位数分边数奇偶考虑,当当边数为num=奇时,结果就算路径第num/2+1大,用主席树做即可... (做了几道比较难的主席树,都wa了...只有来刷刷水题,准备晚上的CF了) #include<bits/stdc++.h> using namespace std; const int maxn=1000010; int Laxt[maxn],Next[maxn],To[maxn],cost[maxn],cnt; int fa[50