bzoj 3545: [ONTAK2010]Peaks(离线处理+并查集+主席树)

3545: [ONTAK2010]Peaks

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 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

Sample Output

6
1
-1
8


HINT

【数据范围】

N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

Source

[ Submit][ Status][ Discuss]


题解:离线处理+并查集+主席树

这个题的做法参照 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]);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值