Peaks
题目描述
在 Bytemountains 有 \(n\) 座山峰,每座山峰有他的高度 \(h_i\)。有些山峰之间有双向道路相连,共 \(m\) 条路径,每条路径有一个困难值,这个值越大表示越难走。
现在有 \(q\) 组询问,每组询问询问从点 \(v\) 开始只经过困难值小于等于 \(x\) 的路径所能到达的山峰中第 \(k\) 高的山峰,如果无解输出 \(-1\)。
输入格式
第一行三个数 \(n,m,q\)。
第二行 \(n\) 个数,第 \(i\) 个数为 \(h_i\)。
接下来 \(m\) 行,每行三个整数 \(a,b,c\),表示从 \(a \to b\) 有一条困难值为 \(c\) 的双向路径。
接下来 \(q\) 行,每行三个数 \(v,x,k\),表示一组询问。
输出格式
对于每组询问,输出一个整数表示能到达的山峰中第 \(k\) 高的山峰的高度。
样例 #1
样例输入 #1
10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
样例输出 #1
6
1
-1
8
提示
数据规模与约定
对于 \(100\%\) 的数据,\(n \le 10^5\),\(0 \le m,q \le 5\times 10^5\),\(h_i,c,x \le 10^9\)。
解题思路
看到要经过边都要小于等于 \(x\) ,我们可以想到 \(kruskal\) 重构树。
对原图建一棵重构树,其结构为原节点在叶子,新建的节点代表的权值即为替代的边权。
采用欧拉序的思想,如果我们只对叶子编号的话,那么从某个点开始经过边权小于等于 \(x\) 的边的点集是连续的。
那么每次求答案,我们可以先用倍增跳到重构树上一个节点,其点权小于等于 \(x\) ,那么这颗节点的子树的叶子即为原图上能到达的点。
一段区间求 \(k\) 大,用主席树即可。
时间复杂度 \(O(nlogn)\) 。
Code
#include<bits/stdc++.h>
using namespace std;
struct edge
{
int x,y,z;
}ed[500005];
struct datay
{
int lc,rc,v;
}a[5000005];
int n,num,m,v[200005],m1,ft[200005],dfn[200005],out[200005],f[200005][21],f1[200005][21],re[200005],d[100005],num1,root[100005];
vector<int> t[200005];
map<int,int> p;
set<int> g;
bool cmp(edge q,edge w)
{
return q.z<w.z;
}
int check(int x)
{
if(ft[x]!=x)ft[x]=check(ft[x]);
return ft[x];
}
void dfs(int x,int y)
{
f[x][0]=ft[x]=y;
if(t[x].size()==0)
{
dfn[x]=out[x]=++num;
return;
}
dfn[x]=num+1;
for(int i=0;i<t[x].size();i++)
{
if(t[x][i]==y)continue;
dfs(t[x][i],x);
f1[t[x][i]][0]=v[x];
}
out[x]=num;
return;
}
int build(int l,int r)
{
if(l==r)
{
return (++num1);
}
int mid=(l+r)>>1,h=++num1;
a[h].lc=build(l,mid);
a[h].rc=build(mid+1,r);
return h;
}
int dijah(int x,int l,int r,int k,int v)
{
int h=++num1;
a[h]=a[x];
if(l==r)
{
a[h].v++;
return h;
}
int mid=(l+r)>>1;
if(k<=mid)a[h].lc=dijah(a[x].lc,l,mid,k,v);
else a[h].rc=dijah(a[x].rc,mid+1,r,k,v);
a[h].v=a[a[h].lc].v+a[a[h].rc].v;
return h;
}
int gaia(int x1,int x2,int l,int r,int k)
{
if(l==r)return l;
int mid=(l+r)>>1;
if(a[a[x2].rc].v-a[a[x1].rc].v>=k)return gaia(a[x1].rc,a[x2].rc,mid+1,r,k);
return gaia(a[x1].lc,a[x2].lc,l,mid,(k-(a[a[x2].rc].v-a[a[x1].rc].v)));
}
int main()
{
int x,y,z,o,g1=0;
scanf("%d%d%d",&n,&m,&m1);
o=n;
for(int i=1;i<=n;i++)scanf("%d",&v[i]),g.insert(v[i]);
set<int>::iterator q=g.begin();
for(;q!=g.end();q++)
{
p[*q]=++g1;
d[g1]=*q;
}
for(int i=1;i<=n;i++)v[i]=p[v[i]];
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
}
sort(ed+1,ed+m+1,cmp);
for(int i=1;i<=2*n;i++)ft[i]=i;
for(int i=1;i<=m;i++)
{
x=check(ed[i].x);
y=check(ed[i].y);
if(x!=y)
{
t[++o].push_back(x);
t[o].push_back(y);
ft[x]=ft[y]=o;
v[o]=ed[i].z;
}
}
for(int i=0;i<=20;i++)f1[o][i]=1e9+5;
dfs(o,0);
for(int i=1;i<=20;i++)
{
for(int j=1;j<=o;j++)f[j][i]=f[f[j][i-1]][i-1],f1[j][i]=max(f1[j][i-1],f1[f[j][i-1]][i-1]);
}
for(int i=1;i<=n;i++)
{
re[dfn[i]]=i;
}
root[0]=build(1,n);
for(int i=1;i<=n;i++)
{
root[i]=dijah(root[i-1],1,n,v[re[i]],1);
}
for(int i=1;i<=m1;i++)
{
scanf("%d%d%d",&x,&y,&z);
for(int j=20;j>=0;j--)
{
if(f1[x][j]<=y)x=f[x][j];
}
if(out[x]-dfn[x]+1<z)
{
printf("-1\n");
continue;
}
g1=gaia(root[dfn[x]-1],root[out[x]],1,n,z);
printf("%d\n",d[g1]);
}
return 0;
}
标签:10,return,Peaks,int,题解,++,rc,P4197,200005
From: https://www.cnblogs.com/dijah/p/17984474