3545: [ONTAK2010]Peaks
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1082 Solved: 289
[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。
我们可以离线处理,对于边的权值大小和询问的权值大小进行排序。这样处理到一个权值为x的询问时,把边加到权值<=x的。
这样用平衡树维护每一个联通块,当两个联通块合并起来的时候,平衡树直接启发式合并一下就行了。
时间复杂度时O(nlog^2n)的。
3551: [ONTAK2010]Peaks加强版
加强版要求强制在线。我们其实可以发现,有用的边只是这个图的最小生成树上面的。
所以,我们求一遍最小生成树,对于其中的一条边,我们新建一个节点,权值为这条边的权值,然后分别连向这两个点,删去原来的边。
这样我们就建出了一棵树,这棵树的叶子节点都是原图中的节点,而且满足大根堆得性质。
这样对于一个询问x,v,k只需要从x向上倍增到最浅的比v小的祖先,这个祖先的子树中的叶子节点就是点x所能到的所有的原图上面的点。
所以我们只需要先预处理出来dfs序,对于dfs序建一个主席树,然后每次询问直接查区间第k大就行了。
3545code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
const int M=1000010;
int t,n,m,p,v[N],fa[N];
struct S{int st,en,va;}l[M];
struct Q{int x,v,k,No,ans;}q[M];
inline int in(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline bool cmp_1(S x,S y){return x.va<y.va;}
inline bool cmp_2(Q x,Q y){return x.v<y.v;}
inline bool cmp_3(Q x,Q y){return x.No<y.No;}
inline int find(int x){
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
struct Node{
Node*ch[2];
int num,r,v,s;
Node(int v):v(v){num=1;ch[0]=ch[1]=NULL;r=rand();}
int cmp(int x) const{
if(x==v) return -1;
else return (x<v?1:0);
}
void Maintain(){
s=num;
if(ch[0]!=NULL) s+=ch[0]->s;
if(ch[1]!=NULL) s+=ch[1]->s;
}
};
Node *root[N];
void rotate(Node* &o,int d){
Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
o->Maintain(); k->Maintain(); o=k;
}
void insert(Node* &o,int x){
if(o==NULL) o=new Node(x);
else {
int d=o->cmp(x);
if(d==-1) o->num+=1;
else{
insert(o->ch[d],x);
if(o->r < o->ch[d]->r) rotate(o,d^1);
}
}
o->Maintain();
}
void del(Node* &o,int x){
int d=o->cmp(x);
if(d==-1){
if(o->num==1){
if(o->ch[0]==NULL) o=o->ch[1];
else if(o->ch[1]==NULL) o=o->ch[0];
else{
int d2=(o->ch[0]->r > o->ch[1]->r?1:0);
rotate(o,d2); del(o->ch[d2],x);
}
}
else o->num-=1;
}
else del(o->ch[d],x);
if(o!=NULL) o->Maintain();
}
int kth(Node* &o,int x){
if(x<=0||x>o->s||o==NULL) return 0;
int d=(o->ch[0]==NULL?0:o->ch[0]->s);
if(d+1<=x&&x<=d+o->num) return o->v;
if(x<=d) return kth(o->ch[0],x);
else return kth(o->ch[1],x-d-o->num);
}
int main(){
int i,j,now=1,x,y;
t=in();n=in();m=in();p=in();
for(i=1;i<=n;++i) v[i]=in();
for(i=1;i<=m;++i) l[i].st=in(),l[i].en=in(),l[i].va=in();
sort(l+1,l+m+1,cmp_1);
for(i=1;i<=p;++i) q[i].x=in(),q[i].v=in(),q[i].k=in(),q[i].No=i;
sort(q+1,q+p+1,cmp_2);
for(i=1;i<=n;++i) fa[i]=i,insert(root[i],v[i]);
for(i=1;i<=p;++i){
for(;l[now].va<=q[i].v&&now<=m;++now){
x=l[now].st,y=l[now].en;
int r1=find(x),r2=find(y);
if(r1==r2) continue;
if(root[r1]->s < root[r2]->s) swap(r1,r2);
fa[r2]=r1;
int xx=root[r2]->s;
while(xx){
int yy=kth(root[r2],xx);
insert(root[r1],yy);
xx-=1;
}
}
x=find(q[i].x);
if(root[x]->s >= q[i].k) q[i].ans=kth(root[x],q[i].k);
else q[i].ans=-1;
}
sort(q+1,q+p+1,cmp_3);
for(i=1;i<=p;++i) printf("%d\n",q[i].ans);
}
3551code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x7fffffff
const int N=200010;
const int M=500010;
const int O=5000000;
struct S{int st,en,va;}aa[N<<1],p[M];
int root[O],l[O],r[O],sum[O],point[N],next[N<<1],use[N],to[N],ans;
int n,m,q,v[N],Fa[N],Root,h[N],minn[N],maxn[N],dfsn,fa[N][20],deep[N],map[N],tot;
inline int in(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline bool cmp(S x,S y){return x.va<y.va;}
inline int find(int x){
if(x!=Fa[x]) Fa[x]=find(Fa[x]);
return Fa[x];
}
inline void add(int x,int y){
tot+=1;next[tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;
tot+=1;next[tot]=point[y];point[y]=tot;
aa[tot].st=y;aa[tot].en=x;
}
inline void dfs(int x,int last){
int i;
for(i=1;i<=19&&deep[x]>=(1<<i);++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
if(x<=n) minn[x]=maxn[x]=++dfsn,map[dfsn]=x;
else minn[x]=inf,maxn[x]=0;
for(i=point[x];i;i=next[i])
if(aa[i].en!=last){
fa[aa[i].en][0]=x;
deep[aa[i].en]=deep[x]+1;
dfs(aa[i].en,x);
minn[x]=min(minn[x],minn[aa[i].en]);
maxn[x]=max(maxn[x],maxn[aa[i].en]);
}
}
#define mid (L+R)/2
inline void insert(int L,int R,int x,int &y,int z){
y=++tot;
sum[y]=sum[x]+1;
if(L>=R) return ;
l[y]=l[x];r[y]=r[x];
if(z<=mid) insert(L,mid,l[x],l[y],z);
else insert(mid+1,R,r[x],r[y],z);
}
inline void query(int L,int R,int x,int y,int z){
int now=sum[l[y]]-sum[l[x]];
if(L==R){
ans=to[L];
printf("%d\n",ans);
return ;
}
if(now<z) query(mid+1,R,r[x],r[y],z-now);
else query(L,mid,l[x],l[y],z);
}
int main(){
int i,j,x,y,z,num=0,lca,size;
n=in();m=in();q=in();Root=n;
for(i=1;i<=n;++i) h[i]=in(),use[i]=h[i];
sort(use+1,use+n+1);
size=unique(use+1,use+n+1)-use-1;
for(i=1;i<=n;++i)
x=h[i],h[i]=upper_bound(use+1,use+size+1,h[i])-use-1,to[h[i]]=x;
for(i=1;i<=m;++i) p[i].st=in(),p[i].en=in(),p[i].va=in();
sort(p+1,p+m+1,cmp);
for(i=1;i<=n*2;++i) Fa[i]=i;
for(i=1;i<=m;++i){
x=p[i].st,y=p[i].en;
int r1=find(x),r2=find(y);
if(r1!=r2){
++num;
add(++Root,r1);add(Root,r2);
Fa[r1]=Fa[r2]=Root;v[Root]=p[i].va;
}
if(num==n-1) break;
}
dfs(Root,0);
for(tot=0,i=1;i<=n;++i) insert(1,size,root[i-1],root[i],h[map[i]]);
while(q--){
x=in();y=in();z=in();
if(ans!=-1) x^=ans,y^=ans,z^=ans;
for(i=19;~i;--i)
if(deep[x]>=(1<<i)&&v[fa[x][i]]<=y) x=fa[x][i];
if(maxn[x]-minn[x]+1<z){printf("-1\n");ans=-1;continue;}
query(1,size,root[minn[x]-1],root[maxn[x]],maxn[x]-minn[x]+2-z);
}
}