JZOJ 5385. 【NOIP2017提高A组模拟9.23】Carry

11 篇文章 0 订阅
9 篇文章 0 订阅

Description

Description

Input

Input

Output

Output

Sample Input

7 7 155
2 1 260
3 2 904
4 2 360
5 2 230
6 5 247
7 5 501
1 3
6 7
2 6
3 1
3 4
4 3
2 4

Sample Output

4104

Data Constraint

Data Constraint

Solution

  • 显然,要改的边一定是在某条路径上最大值上,否则答案将得不到改变。

  • 但又发现 最大值-L<次大值 的话,答案将不是那个最大值,而是那么次大值。

  • 于是用倍增算出这 Q 条路径上的 最大值、次大值的边的编号。

  • 接着按最大值的编号从小到大排一遍序,则相同编号的边可以一起处理(表示一起删除)。

  • 那么把每种方案娶一个最小值即为答案,O((N+Q) log N)

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+1;
struct data
{
    int x,y;
}c[N],t;
int tot=1;
long long ans,all;
int first[N],next[N<<1],en[N<<1],w[N<<1];
int f[N][17],g[N][17],h[N][17];
int a[N],b[N],dep[N];
inline int read()
{
    int X=0,w=1; char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
inline void insert(int x,int y,int z)
{
    next[++tot]=first[x];
    first[x]=tot;
    en[tot]=y;
    w[tot]=z;
}
inline void dfs(int x)
{
    dep[x]=dep[f[x][0]]+1;
    for(int i=first[x];i;i=next[i])
        if(en[i]!=f[x][0])
        {
            f[en[i]][0]=x;
            g[en[i]][0]=i;
            dfs(en[i]);
        }
}
inline data lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    t.x=t.y=0;
    for(int i=log2(dep[x]);i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
        {
            if(w[g[x][i]]>=w[t.x])
            {
                if(w[t.x]>w[h[x][i]]) t.y=t.x; else t.y=h[x][i];
                t.x=g[x][i];
            }else
                if(w[g[x][i]]>w[t.y]) t.y=g[x][i];
            x=f[x][i];
        }
    if(x==y) return t;
    for(int i=log2(dep[x]);i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            if(w[g[x][i]]>=w[t.x])
            {
                if(w[t.x]>w[h[x][i]]) t.y=t.x; else t.y=h[x][i];
                t.x=g[x][i];
            }else
                if(w[g[x][i]]>w[t.y]) t.y=g[x][i];
            if(w[g[y][i]]>=w[t.x])
            {
                if(w[t.x]>w[h[y][i]]) t.y=t.x; else t.y=h[y][i];
                t.x=g[y][i];
            }else
                if(w[g[y][i]]>w[t.y]) t.y=g[y][i];
            x=f[x][i],y=f[y][i];
        }
    if(w[g[x][0]]>=w[t.x])
    {
        if(w[t.x]>w[h[x][0]]) t.y=t.x; else t.y=h[x][0];
        t.x=g[x][0];
    }else
        if(w[g[x][0]]>w[t.y]) t.y=g[x][0];
    if(w[g[y][0]]>=w[t.x])
    {
        if(w[t.x]>w[h[y][0]]) t.y=t.x; else t.y=h[y][0];
        t.x=g[y][0];
    }else
        if(w[g[y][0]]>w[t.y]) t.y=g[y][0];
    return t;
}
inline bool cmp(data x,data y)
{
    return x.x>y.x;
}
int main()
{
    int n=read(),q=read(),l=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read();
        insert(x,y,z);
        insert(y,x,z);
    }
    dfs(1);
    for(int j=1;j<17;j++)
        for(int i=1;i<=n;i++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            if(w[g[i][j-1]]>w[g[f[i][j-1]][j-1]])
            {
                g[i][j]=g[i][j-1];
                if(w[h[i][j-1]]>w[g[f[i][j-1]][j-1]]) h[i][j]=h[i][j-1]; else h[i][j]=g[f[i][j-1]][j-1];
            }else
            {
                g[i][j]=g[f[i][j-1]][j-1];
                if(w[g[i][j-1]]>w[h[f[i][j-1]][j-1]]) h[i][j]=g[i][j-1]; else h[i][j]=h[f[i][j-1]][j-1];
            }
        }
    for(int i=1;i<=q;i++)
    {
        a[i]=read(),b[i]=read();
        c[i]=lca(a[i],b[i]);
        all+=w[c[i].x];
    }
    sort(c+1,c+1+q,cmp);
    ans=all;
    for(int i=1;i<=q;i++)
    {
        int k=i;
        long long sum=all;
        sum-=l;
        if(w[c[i].y]+l>w[c[i].x]) sum+=w[c[i].y]+l-w[c[i].x];
        while(k<q && c[k+1].x==c[i].x)
        {
            k++;
            sum-=l;
            if(w[c[k].y]+l>w[c[k].x]) sum+=w[c[k].y]+l-w[c[k].x];
        }
        if(sum<ans) ans=sum;
        i=k;
    }
    printf("%lld",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值