OVOO

题目描述:

$zhx$有一个棵$n$个点的树,每条边有个权值。

定义一个连通块为一个点集与使这些点连通的所有边(这些点必须连通)。

定义一个连通块的权值为这个连通块的边权和(如果一个连通块只包含一个点,那么它的权值为$0$)。

$zhx$想找一个包含$1$号点的连通块送给他的妹子,所以他希望你求出包含$1$号点的所有连通块中权值第$k$小的连通块的权值。

题解:

非常裸的可持久化可并堆。

经典的$k$短路要求维护绕多远+终点,而它维护总边权+可选边集。

维护边集时需要可持久化可并堆。

还是经典操作,要么扔掉上一条边换上次优,要么在边集中找一个最优然后更新边集。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100050;
const int MOD = 998244353;
const int M = 50*N;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,k,rt[N],wy[M];
ll ww[M];
struct edc
{
    int x;
    ll d;
    edc(){}
    edc(int x,ll d):x(x),d(d){}
    friend bool operator < (edc a,edc b)
    {
        return a.d>b.d;
    }
}tp;
int tot,tw;
struct node
{
    int ls,rs,dis,tl;
    ll v;
}p[M];
int merge1(int x,int y)
{
    if(!x||!y)return x+y;
    if(p[x].v>p[y].v)swap(x,y);
    p[x].rs = merge1(p[x].rs,y);
    if(p[p[x].ls].dis<p[p[x].rs].dis)swap(p[x].ls,p[x].rs);
    p[x].dis=p[p[x].rs].dis+1;
    return x;
}
int merge(int x,int y)
{
    if(!x||!y)return x+y;
    if(p[x].v>p[y].v)swap(x,y);
    int u = ++tot;
    p[u] = p[x],p[u].rs = merge(p[u].rs,y);
    if(p[p[u].ls].dis<p[p[u].rs].dis)swap(p[u].ls,p[u].rs);
    p[u].dis = p[p[u].rs].dis+1;
    return u;
}
priority_queue<edc>q;
ll ans;
int main()
{
    freopen("tt.in","r",stdin);
    read(n),read(k);
    for(int f,w,i=1;i<n;i++)
    {
        read(f),read(w);
        p[++tot].dis=1,p[tot].tl=i+1,p[tot].v=w;
        rt[f] = merge1(rt[f],tot);
    }
    k--;
    tw=1;
    ww[tw] = p[rt[1]].v;
    wy[tw] = rt[1];
    q.push(edc(1,ww[1]));
    while(k&&!q.empty())
    {
        tp = q.top();
        q.pop();
        k--;
        int u = tp.x;
        ans = ww[u];
        if(!k)break;
        int ls = p[wy[u]].ls,rs = p[wy[u]].rs;
        int tmp = merge(ls,rs);
        if(tmp)
        {
            tw++;
            ww[tw] = ww[u]-p[wy[u]].v+p[tmp].v;
            wy[tw] = tmp;
            q.push(edc(tw,ww[tw]));
        }
        tw++;
        wy[tw] = merge(tmp,rt[p[wy[u]].tl]);
        ww[tw] = ww[u]+p[wy[tw]].v;
        if(wy[tw])q.push(edc(tw,ww[tw]));
    }
    printf("%lld\n",ans%MOD);
    return 0;
}

 

posted @ 2019-01-20 16:23  LiGuanlin  阅读(414)  评论(0编辑  收藏  举报