Problem I – Imperial roads —— 树上主席树+lca+

13 篇文章 0 订阅
6 篇文章 0 订阅

The roads of Cubiconia are in a dire state, after years of neglect and lack of maintenance. Each road
connects two different cities A and B and can be traveled in both ways (from A to B or from B to
A). There is at most one road between each pair of cities, and using the existing roads it is possible
to travel between any pair of cities. The new emperor of Cubiconia has just raised the taxes (again!),
but promised to repair at least some of the roads, guaranteeing that Cubiconians will be able to travel
between any pair of cities using only restored roads.
The Department of Public Works have calculated the cost of repairing each individual road. Now
they want to calculate the minimum cost for repairing a set of roads so that the emperor’s promise
is made true. This is not easy because the emperor wants the set of repaired roads to include one
particular road, but he has not yet decided which particular road to include: could be the one that
connects the city where his castle is to the city where his daughter’s royal residence is, or the road that
connects the city where his summer palace is to the only city by the seaside, or. . . Fearing the emperor
will take too long to decide, the engineers want your help.
Given the description of the roads in Cubiconia, with their respective repairing costs, you must write
a program to answer a set of queries. For each query you will be given one specific road that should be
repaired, and must determine the minimum cost for repairing a set of roads (including the given specific
road) so that Cubiconians will be able to travel between any pair of cities using only restored roads.
Input
The first line contains two integers N (2 ≤ N ≤ 105
) and R (N − 1 ≤ R ≤ 2 × 105
), representing
respectively the number of cities and the number of roads in Cubiconia. Cities are identified by distinct
integers from 1 to N. Each of the next R lines describes a road with three integers A, B (1 ≤ A < B ≤ N)
and C (1 ≤ C ≤ 104
), indicating that there is a road between cities A and B and the cost of repairing
it is C. There is at most one road between each pair of cities, and using the existing roads it is
possible to travel between any pair of cities. The next line contains an integer Q (1 ≤ Q ≤ 105
)
representing the number of queries. Each of the next Q lines describes a query with two integers U
and V (1 ≤ U < V ≤ N), indicating the specific road that should be repaired. There are no repeated
queries.
Output
Output Q lines, each line with an integer indicating the answer to the corresponding query of the
input, that is, the minimum cost for repairing a set of roads (including the specific road in the query)
so that Cubiconians will be able to travel between any pair of cities using only restored roads.
Sample input 1
3 3
1 2 10
2 3 5
1 3 7
3
2 3
1 2
1 3
Sample output 1
12
15
12
Sample input 2
4 4
1 2 1
2 4 1
2 3 100
1 4 50
1
1 4
Sample output 2
151
18 ICPC Latin American Regional – 2017
Sample input 3
5 7
1 2 8
1 3 10
2 4 5
2 3 12
4 5 4
3 5 14
1 5 20
3
2 3
1 5
3 5
Sample output 3
29
39
31

题意:

有n个点,m条边,k个询问,问你如果一定使x直接到y那么所有的地点都能到达的最小费用是多少。

题解:

先做一遍最小生成树,然后一定要连x,y的时候我们只需要把x到y之间最大的一条边给去掉,那么就是最小花费。用主席树记录它的父节点与他之间的关系,由于无法求最大值,那么就像求第k大那样,每次更新都+1,由于他的范围不会超过1e4,不用离散化。x到y之间的最大值就是x到lca的最大值和y到lca的最大值的最大值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
int head[N],fa[N][25],vis[N],cnt,dep[N];
struct node
{
    int to,next;
    ll wei;
}e[N<<1];
struct edge
{
    int u,v;
    ll val;
    bool operator< (const edge& a)const
    {
        return val<a.val;
    }
}edg[N<<1];
void add(int x,int y,int w)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    e[cnt].wei=w;
    head[x]=cnt++;
}
ll sum[N*25];
int ls[N*25],rs[N*25],rt[N],tot;
void update(int l,int r,int root,int last,int pos)
{
    sum[root]=sum[last]+1;
    ls[root]=ls[last];
    rs[root]=rs[last];
    if(l==r)
        return ;
    int mid=l+r>>1;
    if(mid>=pos)
        update(l,mid,ls[root]=++tot,ls[last],pos);
    else
        update(mid+1,r,rs[root]=++tot,rs[last],pos);
}
int query(int l,int r,int root,int last)
{
    if(sum[root]-sum[last]==0)
        return 0;
    if(l==r)
        return l;
    int mid=l+r>>1;
    if(sum[rs[root]]-sum[rs[last]]>0)
        return query(mid+1,r,rs[root],rs[last]);
    else
        return query(l,mid,ls[root],ls[last]);
}
void dfs(int son,int ffa,ll val)
{
    dep[son]=dep[ffa]+1;
    fa[son][0]=ffa;
    update(1,10000,rt[son]=++tot,rt[ffa],val);
    for(int i=head[son];~i;i=e[i].next)
    {
        int ne=e[i].to;
        if(ne==ffa)
            continue;
        dfs(ne,son,e[i].wei);
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
//令x为深度较深的点
    for(int i=16;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
//让x向上走到与y同一深度
    if(x==y)return x; //如果直接是lca,直接返回
    for(int i=16;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
//x,y同时向上走,直到父节点相同
    return fa[x][0]; //返回父节点
}
int f[N];
int finds(int x)
{
    return x==f[x]?f[x]:f[x]=finds(f[x]);
}
map<ll,ll>con[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        f[i]=i;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
        scanf("%d%d%lld",&edg[i].u,&edg[i].v,&edg[i].val),con[edg[i].u][edg[i].v]=con[edg[i].v][edg[i].u]=edg[i].val;
    sort(edg+1,edg+1+m);
    ll minn=0;
    for(int i=1;i<=m;i++)
    {
        int fax=finds(edg[i].u);
        int fay=finds(edg[i].v);
        if(fax!=fay)
        {
            f[fay]=fax;
            minn+=edg[i].val;
            add(edg[i].u,edg[i].v,edg[i].val),add(edg[i].v,edg[i].u,edg[i].val);
        }
    }
    dfs(1,0,0);
    for(int i=1;i<=17;i++)
        for(int j=1;j<=n;j++)
            fa[j][i]=fa[fa[j][i-1]][i-1];
    int q;
    scanf("%d",&q);
    int u,v;
    while(q--)
    {
        scanf("%d%d",&u,&v);
        ll lc=lca(u,v);
        ll maxn=max(query(1,10000,rt[u],rt[lc]),query(1,10000,rt[v],rt[lc]));
        printf("%lld\n",minn-maxn+con[u][v]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值