3551: [ONTAK2010]Peaks加强版
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 2937 Solved: 909
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,表示一组询问。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。
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
10
9
-1
HINT
「数据范围」
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
解析:
原题是权限题,我把题目数据样例以及数据范围都给出来了,良心吧。。。
分析题目我们发现,一个点如果要走尽量多的点,那么一定是沿着最短的边走,也就是说路径一定在最小生成树上。
但是把最小生成树建出来还是不可做。
于是就变得有意思了,还是做最小生成树,但合并两结点x,y的时候新建结点tot,把tot连向fa(x),fa(y)这样建出一棵树,tot的权为该边的边权,自行画图可以发现,这样就能保证原来图中的点都为树中的叶子节点,而对于其余节点,以它为根的子树中的叶子节点保证两两间的距离不超过这个点的点权,于是就可以用类似DFS序的方法用主席树解决了,具体看代码。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,q,size,tot,pr,id;
int p[300005],first[200005],fa[200005],num[100005],val[200005];
int vis[200005],dep[200005],st[200005],ed[200005],a[100005];
int f[200005][20],maxx[200005][20];
int tree[5000005],lc[5000005],rc[5000005],root[300005];
struct shu{int to,next,len;};
shu edge[200005];
struct kru{int s,t,l;};
kru e[500005];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline void lsh()
{
sort(a+1,a+n+1);
int m=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++) num[i]=lower_bound(a+1,a+m+1,num[i])-a;
}
inline int get(int v){return fa[v]==v?v:fa[v]=get(fa[v]);}
inline bool comp(const kru &a,const kru &b){return a.l<b.l;}
inline void build(int x,int y){edge[++size].next=first[x],first[x]=size,edge[size].to=y;}
inline void dfs(int point)
{
vis[point]=1,p[++id]=point;
for(int u=first[point];u;u=edge[u].next)
{
int to=edge[u].to;
dep[to]=dep[point]+1,f[to][0]=point,maxx[to][0]=val[point];
dfs(to);
}
if(point>n) p[++id]=point;
}
inline int find(int x,int lim)
{
for(int i=16;i>=0;i--) if(maxx[x][i]<=lim&&dep[x]>=(1<<i)) x=f[x][i];
return x;
}
inline void add(int fa,int &now,int l,int r,int x)
{
now=++tot,tree[now]=tree[fa]+1,lc[now]=lc[fa],rc[now]=rc[fa];
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) add(lc[fa],lc[now],l,mid,x);
else add(rc[fa],rc[now],mid+1,r,x);
}
inline int Q(int r1,int r2,int l,int r,int k)
{
if(l==r) return a[l];
int mid=(l+r)>>1,sum=tree[lc[r1]]-tree[lc[r2]];
if(k<=sum) return Q(lc[r1],lc[r2],l,mid,k);
else return Q(rc[r1],rc[r2],mid+1,r,k-sum);
}
inline void pre()
{
lsh();tot=n;
sort(e+1,e+m+1,comp);
for(int i=1;i<=2*n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
int fax=get(e[i].s),fay=get(e[i].t);
if(fax==fay) continue;
val[++tot]=e[i].l,fa[fax]=fa[fay]=tot;
build(tot,fax),build(tot,fay);
if(tot==2*n-1) break;
}
for(int i=1;i<=n;i++) if(!vis[i]) dfs(get(i));
for(int j=1;j<=16;j++)
for(int i=1;i<=tot;i++)
if(f[i][j-1])
{
f[i][j]=f[f[i][j-1]][j-1];
maxx[i][j]=max(maxx[i][j-1],maxx[f[i][j-1]][j-1]);
}
tot=0;
for(int i=1;i<=id;i++)
if(p[i]<=n) add(root[i-1],root[i],1,n,num[p[i]]);
else
{
root[i]=root[i-1];
if(!st[p[i]]) st[p[i]]=i;
else ed[p[i]]=i;
}
}
int main()
{
n=get_int(),m=get_int(),q=get_int();
for(int i=1;i<=n;i++) a[i]=num[i]=get_int();
for(int i=1;i<=m;i++) e[i].s=get_int(),e[i].t=get_int(),e[i].l=get_int();
pre();
while(q--)
{
int u=get_int(),x=get_int(),k=get_int();
if(~pr) u^=pr,x^=pr,k^=pr;
int fa=find(u,x),a=root[ed[fa]],b=root[st[fa]];
if(tree[a]-tree[b]<k) print(pr=-1);
else print(pr=Q(a,b,1,n,tree[a]-tree[b]-k+1));
putchar('\n');
}
return 0;
}