BZOJ3545: [ONTAK2010]Peaks
题解:离线排序处理 并查集维护边 对于不同集合的启发式合并平衡树 查询第K大即可
/************************************************************** Problem: 3545 User: c20161007 Language: C++ Result: Accepted Time:9736 ms Memory:19868 kb ****************************************************************/ #include <bits/stdc++.h> #define ll long long const int NM=1e5+10; const int nm=5e5+10; using namespace std; int ch[NM][2],size[NM],key[NM],pre[NM]; int f[NM]; struct FastIO { static const int S=200; int wpos; char wbuf[S]; FastIO():wpos(0){} inline int xchar() { static char buf[S]; static int len=0,pos=0; if(pos==len) pos=0,len=fread(buf,1,S,stdin); if(pos==len) exit(0); return buf[pos++]; } inline int read() { int s=1,c=xchar(),x=0; while(c<=32) c=xchar(); if(c=='-') s=-1,c=xchar(); for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0'; return x*s; } ~FastIO() { if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0; } }io; typedef struct Edge{ int u,v;int vul; friend bool operator<(Edge aa,Edge bb){ return aa.vul<bb.vul; } }Edge; Edge ed[nm]; typedef struct node{ int v,x,k;int id; friend bool operator<(node aa,node bb){ return aa.x<bb.x; } }node; node que[nm]; void newnode(int x){ pre[x]=0;ch[x][0]=ch[x][1]=0;size[x]=1; } int n,m,q; int find1(int x){ if(f[x]==x)return x; else return f[x]=find1(f[x]); } void up(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;} void rotate(int x,int kind){ int y=pre[x]; ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y; if(pre[y])ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y];ch[x][kind]=y;pre[y]=x; up(y); } void splay(int x){ while(pre[x]!=0){ if(pre[pre[x]]==0)rotate(x,ch[pre[x]][0]==x); else{ int y=pre[x];int kind=ch[pre[y]][0]==y; if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } void insert(int &x,int pos,int fa){ if(!x){x=pos;pre[pos]=fa;return ;} if(key[x]>key[pos])insert(ch[x][1],pos,x); else insert(ch[x][0],pos,x); up(x); } int S[NM]; void dfs(int x){ if(!x)return ; S[++S[0]]=x; dfs(ch[x][0]); dfs(ch[x][1]); } void merge(int u,int v){ splay(u);splay(v); if(size[u]>size[v])swap(u,v); S[0]=0;dfs(u);int t=v; for(int i=1;i<=S[0];i++)newnode(S[i]),insert(t,S[i],0),splay(S[i]),t=S[i]; //splay(S[S[0]]); } int find2(int x,int sz){ if(sz==size[ch[x][0]]+1)return x; else if(sz<=size[ch[x][0]])return find2(ch[x][0],sz); else return find2(ch[x][1],sz-size[ch[x][0]]-1); } int querty(int v,int k){ splay(v); if(size[v]<k)return -1; return key[find2(v,k)]; } int ans[nm]; int main(){ n=io.read();m=io.read();q=io.read(); for(int i=1;i<=n;i++)key[i]=io.read(),newnode(i),f[i]=i; for(int i=1;i<=m;i++)ed[i].u=io.read(),ed[i].v=io.read(),ed[i].vul=io.read(); for(int i=1;i<=q;i++)que[i].v=io.read(),que[i].x=io.read(),que[i].k=io.read(),que[i].id=i; sort(ed+1,ed+m+1);sort(que+1,que+1+q); int l=1; for(int i=1;i<=q;i++){ while(l<=m&&que[i].x>=ed[l].vul){ int t1=find1(ed[l].u);int t2=find1(ed[l].v); if(t1!=t2){ merge(t1,t2);f[t1]=t2; } l++; } ans[que[i].id]=querty(que[i].v,que[i].k); } for(int i=1;i<=q;i++)printf("%d\n",ans[i]); return 0; }
3545: [ONTAK2010]Peaks
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3083 Solved: 837
[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。