求第k小的含1号节点的联通块,可以理解为第k小的点集,对于一个点集,他有两种方式拓展,一个是将他的一个边缘节点替换成点集里其他节点延伸出去的最小的边的tail,一个是在点集里新加入一个边缘节点延伸出去的最小的边的tail。
于是我们维护一个点集的优先队列,对于当前的点集按以上两种方式拓展,塞进优先队列里面。
怎么才能知道一个点集边缘节点延伸出去的边的最小值呢?可以打一个可持久化的可并堆维护,每次操作把堆顶的边删掉,合并两个孩子,如果要新加一个节点,合并一下这个节点延伸出去的所有边,每次操作记得维护点集的权值。
这样做的话,优先队列就不需要维护点集,只需要维护当前的权值和以及当前延伸出去的边的堆就行了
有的点可能出度很大,所以每个节点延伸出去的所有边预处理一下,合并在一起。
(怎么感觉我讲的不清楚呢?有什么看不懂的可以留言,我看到都会回复的)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<string>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
void read( LL &x )
{
char c; LL f=1;
while( !( (c=getchar())>='0' && c<='9' ) )
if( c == '-' ) f *= -1;
x = c-'0';
while( (c=getchar())>='0' && c<='9' )
(x*=10) += c-'0';
x *= f;
}
const LL maxn = 2010000;
const LL maxp = 1010000;
const LL Mod = 998244353;
queue< LL >q;
struct edge
{
LL y,c,next;
}a[maxn];
LL len,first[maxp];
void ins( LL x,LL y,LL c )
{
len++;
a[len].y = y; a[len].c = c;
a[len].next = first[x]; first[x] = len;
}
struct node
{
LL lc,rc,c,y,dist;
}tr[maxp*5]; LL total;
LL n,k;
LL newnode( LL c,LL y )
{
total++;
tr[total].lc = tr[total].rc = 0;
tr[total].c = c;
tr[total].y = y;
return total;
}
LL merge( LL x,LL y )
{
if( !x || !y ) return x|y;
if( tr[x].c > tr[y].c ) swap( x,y );
LL ret = ++total;
tr[ret] = tr[x];
LL k = merge( tr[ret].rc,y );
if( tr[tr[ret].lc].dist <= tr[k].dist ) swap( tr[ret].lc,k );
tr[ret].rc = k;
if( k ) tr[ret].dist = tr[k].dist+1;
else tr[ret].dist = 0;
return ret;
}
struct G
{
LL x,d;
};
bool operator <( G x,G y )
{
return x.d > y.d;
}
priority_queue< G >Q;
LL rootp[maxn];
int main()
{
len = 0; memset( first,0,sizeof first );
LL x,y,c;
read( n ); read( k );
for( LL i=2;i<=n;i++ )
{
read( x ); read( y );
ins( x,i,y );
}
q.push( 1 );
while( !q.empty() )
{
x = q.front(); q.pop();
for( LL k=first[x];k;k=a[k].next )
{
y = a[k].y;
rootp[x] = merge( rootp[x],newnode( a[k].c,y ) );
q.push( y );
}
}
//rootp[0] = newnode( 0,1 );
LL ans=0;
G t0;
t0.x = rootp[1]; t0.d = tr[rootp[1]].c;
Q.push( t0 );
k--;
while( k-- )
{
if( Q.empty() ) break;
G now = Q.top(); Q.pop();
ans = now.d;
LL mc = merge( tr[now.x].lc,tr[now.x].rc );
if( mc )
{
G t1;
t1.d = now.d + tr[mc].c - tr[now.x].c;
t1.x = mc;
Q.push( t1 );
}
G t2;
t2.x = merge( mc,rootp[tr[now.x].y] );
t2.d = now.d + tr[t2.x].c;
if( t2.x ) Q.push( t2 );
}
printf("%I64d\n",ans%Mod);
return 0;
}