これは、この事を使用しているものと同様に、来ゆっくりと私に耳を傾ける、もはや不人気なものに人気がありません。
今無向グラフが与えられると、各点は点の権利を有しており、各エッジは右側を有しています。どれだけ今だけYを超えていない右側の側面を取ることができ、Xを取得するための要件から始め、多くのお問い合わせトリプル(X、Y、Z)を得、Zは、右の点の最初の大きなポイント右端にされて到達することができますか?(BZOJ3551)
オフラインの場合、それは達成するために地獄ツリーのカバーの木の会長などのような大物を使用することができ、私は正直、私はしませんと言います!!!
オンラインしかし、もし私たちは、この魔法の事を紹介することができます - クラスカルは、ツリーを再構築します。
クラスカルは、我々はそれは、右の幼稚園になりませんでしょう。
クラスカル原理は最小貪欲側を添加してもよい選択し、各エッジをソートすることです。クラスカルは必ずしも最小に追加される側を選択するので、それによって、それが上記の質問に答える保証する最小スパニングツリーの結論の操作でなければなりません。
ツリーは、各側に、クラスカルの原理に従って再構築されるツリーに直接接続されず、置換ドットを開くために、コンタクトに接続される部分(及びおそらく図原点代替結合点、あるいは接続によって表される2つの点の原点に代わるものとして)。
これは右側からクラスカル参加し始めたので、次に、このように構成されたツリーはルートに葉からインクリメントされなければならない再構築する権利を指す最小2点間の右辺における原画像の右点でありますA。
醜いが、やると右側に番号(右ポイント)、紫色のペンを指すように、青色のペンを参照してください。
次いで、再構成されたツリーを左として生成される(時点tが新たに言うことである置換点、で生成され、原点は、リーフノードに存在します
これは発見されていないこと:ツリーのクラスカル再構成、任意のエッジ重みにサブツリーのリーフノードとの間のすべての経路は、サブルートノードの最大重量を超えていませんか?
各接合縁部は、より大きな重みであり、したがって、別の点について、右側の点は、ツリーの下に、小さいからです。これは、上記の問題は少し考えであるためではないでしょうか?
まずクラスカル木、木を再構築し、次にUのでヴァル[U] <= Y及びヴァル[U]できるだけ大きくを見つけるために、各ノードを乗算構築することができ、我々は魔法を見つけることができるかどうか自然、各ノードは、すべての木のクラスカルの復興と一つだけのリーフノードは、元のとして表示されますか?
その後、我々は木の会長と直接この問題を解決することができます。
因为我们已经求出了节点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; }
完结撒花!!!