Konjac tree-lined review - Kruskal tree reconstruction

This is no longer a popular to unpopular things, as to what use this thing, listen to me slowly come.

Now given an undirected graph, each point has the right to a point, each edge has a right side. Now give many inquiries triples (X, Y, Z), starting from the requirement to obtain X, can only take the side of the right side does not exceed Y, Z can reach the first big point right edge of the right point is how much? (BZOJ3551)

If offline, it can be used bigwigs like hell Chairman of the tree cover tree and the like to achieve, I honestly say I will not! ! !

But if online, then we can introduce this magical thing - Kruskal reconstruct the tree.

Kruskal we will it, will not turn right kindergarten.

Kruskal principle is to sort each edge, then select the minimum greedy side may be added. Because Kruskal selected side necessarily be added to the minimum, thereby ensuring that answer the above question must be in the operation of the conclusions of the minimum spanning tree.

The tree is reconstructed according to the principles of Kruskal, on each side, are not connected directly to the tree, but to open a substitution dot, and a portion to be connected to contact (and possibly a figure origin and an alternate point of attachment, and alternatively as an alternative to the origin point of the two points represented by the connection).

Then this is the right point of the original image in the right side between two points, the smallest since the Kruskal from the right side began to join, then point the right to reconstruct the tree thus constructed must be incremented from the leaves to the root of.

Although ugly, make do and see, blue pen to point number (point right), purple pen to the right side.

Then the reconstructed tree is generated as the left (point t is newly generated with substitution dot, that is to say, the original point exists only in the leaf node

That this is not to be found: the Kruskal reconstruction of the tree, every path between a sub-tree leaf nodes to any edge weight does not exceed the maximum weight of the sub-root node?

Because each joined edges are larger weights, and therefore for the alternative point, right point is smaller, at the bottom of the tree. It is not for the above problem is a little idea?

We can first construct Kruskal reconstructed tree, the tree and then multiplying by each node to find a U so Val [U] <= Y and Val [U] as large as possible, and if we can find a magic nature, each node, all Kruskal reconstruction of a tree and only one leaf node appears as on the original?

Then we can solve this problem directly with the Chairman of the tree.

因为我们已经求出了节点U,保证以U为根的子树内所有叶子节点都可以通过最长边权不超过Y的边到达,那么是否可以将以某个节点为根的子树中所有叶子节点的集合视为一个区间呢?

答案是肯定的,下面就剩下一个主席树维护区间最小值了。不会的请百度搜索《蒟蒻林荫小复习——主席树》即可。

直接用主席树维护克鲁斯卡尔重构树的每个叶子节点,然后根据求出的U选择正确的区间,求值即可。

最后放个代码(蒟蒻林荫写了一晚上这个东西)

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int Val[100001],fa[100001],BZ[100001][26],S[100001],a[100001];
vector<int> b[100001];//重构树
int dfn[100001],low[100001],rk[100001];
//dfn代表每个虚构点的子树所包含的第一个实际点,low代表最后一个
//两者即可控制出一个区间 
struct PE
{
    int u,v,val;
};
PE edge[500001];
struct PES
{
    int ls,rs,sums;
};
PES t[1600001];
int rt[100001];
int n,m,q,cnt,tot,limt,top,num;
bool Function(PE x,PE y)
{
    return x.val<y.val; 
}
int Find(int x)
{
    return fa[x]==x?fa[x]:fa[x]=Find(fa[x]);
}
void DFS(int x,int ff)
{
    if(x<=n)
    {
        dfn[x]=++limt;
        low[x]=limt;
        rk[limt]=x;
    }
    else
    {
        dfn[x]=998244353;
        low[x]=0;
    }
    BZ[x][0]=ff;
    for(int i=b[x].size()-1;i>=0;i--)
    {
        DFS(b[x][i],x);
        dfn[x]=min(dfn[x],dfn[b[x][i]]);
        low[x]=max(low[x],low[b[x][i]]);
    }
}
void ADD(int &x,int l,int r,int p)
{
    t[++num]=t[x];++t[x=num].sums;if(l==r)return;
    int mid=(l+r)>>1;
    if(p<=mid)ADD(t[x].ls,l,mid,p);
    else ADD(t[x].rs,mid+1,r,p);
}
/*int Query(int B2,int B1,int l,int r,int K)
{
    if(l==r)
    {
        return S[l];
    }
    int mid=(l+r)>>1;
    int sum=t[t[B2].rs].sums-t[t[B1].rs].sums;
    if(sum>=K)
    {
        return Query(t[B2].rs,t[B1].rs,mid+1,r,K);
    }
    else
        return Query(t[B2].ls,t[B1].ls,l,mid,K-sum);
}*/
int Query(int A,int B,int l,int r,int K)
{
    if(l==r)return S[l];
    int mid=(l+r)>>1,sum=t[t[A].rs].sums-t[t[B].rs].sums;
    if(sum>=K)return Query(t[A].rs,t[B].rs,mid+1,r,K);
    else return Query(t[A].ls,t[B].ls,l,mid,K-sum);
}
int BZENG()
{
    for(int i=1;i<=19;i++)
    {
        for(int j=1;j<=tot;j++)
        {
            BZ[j][i]=BZ[BZ[j][i-1]][i-1];
        }
    }
}
int main()
{
    freopen("txt.in","r",stdin);
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&S[i]);
        a[i]=S[i];
    }
    sort(S+1,S+1+n);
    top=unique(S+1,S+1+n)-S-1;
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(S+1,S+1+top,a[i])-S;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].val);
    }
    sort(edge+1,edge+1+m,Function);
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
    }
    tot=n;
    for(int i=1;i<=m;i++)
    {
        int u=Find(edge[i].u);
        int v=Find(edge[i].v);
        if(u==v)
        {
            continue;
        }
        ++tot;
        fa[tot]=fa[u]=fa[v]=tot;
        Val[tot]=edge[i].val;
        b[tot].push_back(u);
        b[tot].push_back(v);
    }
    DFS(tot,0);
    BZENG();
    for(int i=1;i<=n;i++)
    {
        ADD(rt[i]=rt[i-1],1,top,a[rk[i]]);
    }
    int lans=0,a1,a2,a3;
    while(q--)
    {
        int v,x,K;
        scanf("%d%d%d",&v,&x,&K);
        if(lans!=-1)v^=lans,x^=lans,K^=lans;
        for(int i=19;~i;--i)
            if(BZ[v][i]&&Val[BZ[v][i]]<=x)
                v=BZ[v][i];
        if(low[v]-dfn[v]+1<K)lans=-1;
        else lans=Query(rt[low[v]],rt[dfn[v]-1],1,top,K);
        printf("%d\n",lans);
    }
    return 0;
}

 

完结撒花!!!

 

Guess you like

Origin www.cnblogs.com/XLINYIN/p/11795960.html
Recommended