bzoj3551 [ONTAK2010]Peaks加强版

Description

//【题目描述】同3545

在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

//同3545

对于每组询问,输出一个整数表示答案。

Sample Input

Sample Output

HINT

//【数据范围】同3545

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

正解:$kruskal$重构树+主席树。

这题的普通版是权限题。。

有一个神奇的东西,叫做$kruskal$重构树。

我们在做最小生成树的时候,并不是直接把两个联通块的根连起来,而是对于两个联通块,新建一个点,连向这两个联通块的根结点,而这个新建点的点权就是这条边的边权。

注意到这样做生成的树有一些性质:

1.这是一棵二叉树。

2.原树点都是叶子结点。

3.子结点比父结点点权小(大根堆)。

4.原树与新树两点间路径最大值与新树相等,且等于新树两点$lca$点权。

然后我们发现,对于任意一个$v$,我们向上找到深度最小的满足点权$<=x$的点,然后查询整个子树的第$k$大,就是答案了。

  1 //It is made by wfj_2048~
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <cstdio>
  7 #include <vector>
  8 #include <cmath>
  9 #include <queue>
 10 #include <stack>
 11 #include <map>
 12 #include <set>
 13 #define inf (1<<30)
 14 #define N (200010)
 15 #define il inline
 16 #define RG register
 17 #define ll long long
 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 19
 20 using namespace std;
 21
 22 struct edge{ int nt,to; }G[N<<1];
 23 struct E{ int u,v,w; }g[N<<2];
 24
 25 int head[N],top[N],fa[N],son[N],dep[N],pos[N],dfn[N],ed[N],sz[N],hsh[N],h[N],d[N];
 26 int sum[20*N],ls[20*N],rs[20*N],rt[N],Sz,n,m,Q,RT,num,cnt,tot,ans;
 27
 28 il int gi(){
 29     RG int x=0,q=1; RG char ch=getchar();
 30     while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar();
 31     if (ch==‘-‘) q=-1,ch=getchar();
 32     while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar();
 33     return q*x;
 34 }
 35
 36 il void insert(RG int from,RG int to){
 37     G[++num]=(edge){head[from],to},head[from]=num; return;
 38 }
 39
 40 il int cmp(const E &a,const E &b){ return a.w<b.w; }
 41
 42 il int find(RG int x){ return (!fa[x] || fa[x]==x) ? x : fa[x]=find(fa[x]); }
 43
 44 il void dfs1(RG int x,RG int p){
 45     fa[x]=p,dep[x]=dep[p]+1,sz[x]=1; RG int v;
 46     for (RG int i=head[x];i;i=G[i].nt){
 47     v=G[i].to; if (v==p) continue;
 48     dfs1(v,x),sz[x]+=sz[v];
 49     if (sz[son[x]]<=sz[v]) son[x]=v;
 50     }
 51     return;
 52 }
 53
 54 il void dfs2(RG int x,RG int p,RG int anc){
 55     top[x]=anc,dfn[x]=++cnt,pos[cnt]=x;
 56     if (son[x]) dfs2(son[x],x,anc); RG int v;
 57     for (RG int i=head[x];i;i=G[i].nt){
 58     v=G[i].to; if (v==p || v==son[x]) continue;
 59     dfs2(v,x,v);
 60     }
 61     ed[x]=cnt; return;
 62 }
 63
 64 il int lca(RG int x,RG int k){
 65     RG int la=x; while (x && d[top[x]]<=k) la=top[x],x=fa[top[x]];
 66     if (d[x]>k || d[top[x]]<=k) return la;
 67     RG int l=dfn[top[x]],r=dfn[x],mid,res;
 68     while (l<=r){
 69     mid=(l+r)>>1;
 70     if (d[pos[mid]]<=k) res=pos[mid],r=mid-1; else l=mid+1;
 71     }
 72     return res;
 73 }
 74
 75 il void add(RG int x,RG int &y,RG int l,RG int r,RG int v){
 76     sum[y=++Sz]=sum[x]+1,ls[y]=ls[x],rs[y]=rs[x];
 77     if (l==r) return; RG int mid=(l+r)>>1;
 78     v<=mid?add(ls[x],ls[y],l,mid,v):add(rs[x],rs[y],mid+1,r,v); return;
 79 }
 80
 81 il int query(RG int x,RG int y,RG int l,RG int r,RG int k){
 82     if (l==r) return hsh[l]; RG int mid=(l+r)>>1,tmp=sum[rs[y]]-sum[rs[x]];
 83     return k<=tmp?query(rs[x],rs[y],mid+1,r,k):query(ls[x],ls[y],l,mid,k-tmp);
 84 }
 85
 86 il void work(){
 87     n=gi(),m=gi(),Q=gi();
 88     for (RG int i=1;i<=n;++i) fa[i]=i,h[i]=gi(),hsh[++tot]=h[i];
 89     sort(hsh+1,hsh+tot+1),tot=unique(hsh+1,hsh+tot+1)-hsh-1;
 90     for (RG int i=1;i<=n;++i) h[i]=lower_bound(hsh+1,hsh+tot+1,h[i])-hsh;
 91     for (RG int i=1;i<=m;++i) g[i].u=gi(),g[i].v=gi(),g[i].w=gi();
 92     sort(g+1,g+m+1,cmp),cnt=n;
 93     for (RG int i=1,k=0,x,y;i<=m;++i){
 94     x=find(g[i].u),y=find(g[i].v); if (x==y) continue;
 95     fa[x]=fa[y]=++cnt,insert(cnt,x),insert(cnt,y);
 96     d[cnt]=g[i].w,RT=cnt,++k; if (k==n-1) break;
 97     }
 98     cnt=0,dfs1(RT,0),dfs2(RT,0,RT);
 99     for (RG int i=1;i<=cnt;++i)
100     if (pos[i]>n) rt[i]=rt[i-1];
101     else add(rt[i-1],rt[i],1,tot,h[pos[i]]);
102     for (RG int i=1,v,x,k,Lca;i<=Q;++i){
103     v=gi()^ans,x=gi()^ans,k=gi()^ans,Lca=lca(v,x);
104     if (sum[rt[ed[Lca]]]-sum[rt[dfn[Lca]-1]]<k) ans=0,puts("-1");
105     else ans=query(rt[dfn[Lca]-1],rt[ed[Lca]],1,tot,k),printf("%d\n",ans);
106     }
107     return;
108 }
109
110 int main(){
111     File("peaks");
112     work();
113     return 0;
114 }
时间: 2024-10-14 00:47:30

bzoj3551 [ONTAK2010]Peaks加强版的相关文章

bzoj3545 [ONTAK2010]Peaks、bzoj3551 [ONTAK2010]Peaks加强版

题目描述: bzoj3545,luogu bzoj3551 题解: 重构树+线段树合并. 可以算是板子了吧. 代码(强制在线): #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; const int M = 5*N; template<typename T> inline void read(T&x) {

bzoj3545/bzoj3551 [ONTAK2010]Peaks/Peaks加强版

传送门:bzoj  bzoj wdnmd为什么加强版不是权限题原题却是啊 3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I

bzoj 3551: [ONTAK2010]Peaks加强版

Description [题目描述]同3545 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 同3545 Sample Input Sample Output HINT [数据范围]同3545 Source

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)

Description [题目描述]同3545 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 同3545 [思路] Kruskal+主席树+dfs序 一个叫kruskal重构树的方法QWQ.在kruskal合

BZOJ 3551 ONTAK2010 Peaks加强版 Kruskal重构树+可持久化线段树

题目大意:同3545 强制在线 3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953 强制在线没法排序 启发式合并也就用不了了 Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题 这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上 比如说样例的树就建成了这样 图中红色的是原图的边权,黑色的是原图上的点 这样生成的树有一些十分优美的性质: 1.二

ONTAK2010 Peaks加强版

给一个图,每个点有点权,$q$ 次询问从 $x$ 开始只走点权小于等于 $y$ 的路径能到的点中第 $k$ 大的点权,无解输出 -1 强制在线 请注意因为这个 sb 博主为了描述方便,这里的题目描述用的字母跟原题有出入,题解跟跟这里的题目描述一样,不一定跟 bzoj 上一样( $n \leq 10^5$ $m,q \leq 5 \times 10^5$ 点权$\leq 10^9$ sol: Kruskal 重构树,每次能走的是一个子树 于是我们可以先倍增找到能走的最高的点(倍增找到重构树上点权小

dtoi1927 [ONTAK2010]Peaks加强版

题意: 给一个n个点的图,每个点有权值,每条边有权值.q次询问,每次询问从a出发不经过边权大于x的边能够到达的所有点中,点权第k大的值. n<=100000,q<=500000 题解:      点权第k大的值,容易想到可持久化线段树,问题就在于如何把要查询的点转化为一段连续的区间. 考虑建立Kruskal重构树.这种树有一个性质,经过两个点的路径的边权最大值就是在重构树上的lca的点权. 因此可以倍增a的父亲到达最后一个点权小于等于x的节点,然后所有能到达的点就是其子树. 那么就在dfs序上