3545: [ONTAK2010]Peaks
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1626 Solved: 441
[ Submit][ Status][ Discuss]
Description
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
Input
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
Output
对于每组询问,输出一个整数表示答案。
Sample Input
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 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
Sample Output
6
1
-1
8
1
-1
8
HINT
【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
Source
题解:离线处理+并查集+主席树
这个题的做法参照 bzoj 2333棘手的操作
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 500030
#define M 200003
using namespace std;
struct data
{
int x,y,k,v,pos;
}a[N],e[N];
int h[M],n,m,q,fa[M],end[M],next[M],tot,b[M],c[M],num[M],sz,pos[M],val[M],root[M],ans[N];
struct tree
{
int l,r,w;
}tr[M*30];
int cmp(data a,data b)
{
return a.v<b.v;
}
int cmp1(int x,int y)
{
return h[x]<h[y];
}
void insert(int &i,int l,int r,int pos)
{
tr[++tot]=tr[i]; i=tot;
tr[i].w++;
if (l==r) return;
int mid=(l+r)/2;
if (pos<=mid) insert(tr[i].l,l,mid,pos);
else insert(tr[i].r,mid+1,r,pos);
}
int query(int i,int j,int l,int r,int k)
{
int t=tr[tr[j].l].w-tr[tr[i].l].w;
if (l==r) return l;
int mid=(l+r)/2;
if (t>=k) query(tr[i].l,tr[j].l,l,mid,k);
else query(tr[i].r,tr[j].r,mid+1,r,k-t);
}
int find(int x)
{
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++) scanf("%d",&h[i]),b[i]=i;
sort(b+1,b+n+1,cmp1);
int cnt1=0;
for (int i=1;i<=n;i++)
c[b[i]]=i,num[i]=h[b[i]];
for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
for (int i=1;i<=q;i++) {
int x,k,v; scanf("%d%d%d",&x,&v,&k);
e[i].pos=i;
e[i].x=x; e[i].v=v; e[i].k=k;
}
sort(a+1,a+m+1,cmp);
sort(e+1,e+q+1,cmp);
for (int i=1;i<=n;i++) fa[i]=i,end[i]=i;
int cnt=sz;
for (int i=1;i<=m;i++)
{
int r1=find(a[i].x); int r2=find(a[i].y);
if (r1!=r2) {
fa[r2]=r1;
next[end[r1]]=r2;
end[r1]=end[r2];
}
}
sz=0;
for (int i=1;i<=n;i++)
if (find(i)==i) {
for(int j=i;j;j=next[j])
pos[j]=++sz,val[sz]=c[j];
}
//for (int i=1;i<=n;i++) cout<<val[i]<<" ";
//cout<<endl;
for (int i=1;i<=n;i++) {
root[i]=root[i-1];
insert(root[i],1,n,val[i]);
}
for (int i=1;i<=n;i++) fa[i]=i,end[i]=i;
int l=1;
for (int i=1;i<=q;i++) {
while (a[l].v<=e[i].v&&l<=m) {
int r1=find(a[l].x); int r2=find(a[l].y);
if (r1!=r2) {
fa[r2]=r1;
next[end[r1]]=r2;
end[r1]=end[r2];
}
l++;
}
int t=find(e[i].x); //cout<<a[i].x<<" ";
int l=pos[t]-1; //cout<<end[t]<<endl;
int r=pos[end[t]]; //cout<<l<<" "<<r<<endl;
if (tr[root[r]].w-tr[root[l]].w<e[i].k) ans[e[i].pos]=-1;
else {
int size=tr[root[r]].w-tr[root[l]].w;
int t=query(root[l],root[r],1,n,size-e[i].k+1); //cout<<t<<endl;
ans[e[i].pos]=num[t];
}
}
for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
}