码迷,mamicode.com
首页 > 其他好文 > 详细

Bzoj3545 [ONTAK2010]Peaks

时间:2017-04-01 20:34:39      阅读:308      评论:0      收藏:0      [点我收藏+]

标签:name   二叉树   div   memory   printf   改变   algorithm   swa   shu   

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2038  Solved: 535

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

 

Kruskal  启发式合并 树 treap 脑洞题

将询问离线,按询问x值从小到大排序,回答每个询问前将x值小于询问值的边加进集合,进行启发式合并。

用treap维护集合内的结点,进行排名查询以回答询问。

 

算法比较好想,然而并不会写treap的启发式合并……

各种开脑洞,发现要么太难实现,要么实现了不能保证二叉树性质WAWAWA

依稀记得听说过可持久化treap的合并是以某个权值为界把treap拆分开,再合并成一整棵新树,想想就好难写。

最后放弃了挣扎,选择了暴力把一棵treap上的点全建到另一棵treap上。

然而一对拍又挂了,检查了好久好久,发现合并时候少传了一个地址。

于是一下午+半个晚上就水过去了。

 

随机数种子很好用,并没有特殊的意义(认真脸)

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 using namespace std;
  9 const int mxn=120010;
 10 int read(){
 11     int x=0,f=1;char ch=getchar();
 12     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}
 13     while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
 14     return x*f;
 15 }
 16 struct edge{
 17     int x,y,w;
 18     bool operator < (edge b)const{return w<b.w;}
 19 }e[mxn*5];
 20 struct QUE{
 21     int v,x,k,id;
 22     bool operator < (QUE b)const{return x<b.x;}
 23 }q[mxn*5];
 24 //
 25 int fa[mxn],sz[mxn];
 26 int find(int x){
 27     return fa[x]==x?x:fa[x]=find(fa[x]);
 28 }
 29 //
 30 struct node{
 31     int l,r;
 32     int v,sz,cnt;
 33     int rand;
 34 }t[mxn*5];
 35 int rot[mxn],cnt;
 36 void pushup(int x){
 37     t[x].sz=t[t[x].l].sz+t[t[x].r].sz+t[x].cnt;
 38 }
 39 void Rt(int &k){
 40     int now=t[k].l;
 41     t[k].l=t[now].r;
 42     t[now].r=k;
 43     pushup(k);pushup(now);
 44     k=now;
 45     return;
 46 }
 47 void Lt(int &k){
 48     int now=t[k].r;
 49     t[k].r=t[now].l;
 50     t[now].l=k;
 51     pushup(k);pushup(now);
 52     k=now;
 53     return;
 54 }
 55 void DEBUG(){
 56     printf("Debug\n");
 57     for(int j=0;j<=cnt;j++){
 58         printf("#%d: lc:%d rc:%d sz:%d cnt:%d\n",j,t[j].l,t[j].r,t[j].sz,t[j].cnt);
 59     }
 60     printf("fin\n");
 61     return;
 62 }
 63 int bin[mxn*2],top=0;
 64 void insert(int v,int c,int &rt){
 65     if(!rt){
 66         if(top)rt=bin[top--];
 67         else rt=++cnt;
 68         t[rt].cnt=t[rt].sz=c;
 69         t[rt].v=v;
 70         t[rt].rand=rand();
 71         t[rt].l=t[rt].r=0;
 72         return;
 73     }
 74     t[rt].sz+=c;
 75     if(t[rt].v==v) t[rt].cnt+=c;
 76     else if(v<t[rt].v){
 77         insert(v,c,t[rt].l);
 78         if(t[t[rt].l].rand>t[rt].rand){
 79             Rt(rt);
 80         }
 81     }
 82     else{
 83         insert(v,c,t[rt].r);
 84         if(t[t[rt].r].rand>t[rt].rand){
 85             Lt(rt);
 86         }
 87     }
 88     return;
 89 }
 90 void Merge(int &x,int &y){//y也会被改变,需要传地址 
 91     if(!x)return;
 92     Merge(t[x].l,y);
 93     Merge(t[x].r,y);
 94     int tmp=x;
 95     x=0;
 96     insert(t[tmp].v,t[tmp].cnt,y);
 97     bin[++top]=tmp;
 98     return;
 99 }
100 int ask_rank(int rt,int k){
101     if(!rt)return 0;
102     if(t[t[rt].r].sz>=k)return ask_rank(t[rt].r,k);
103     else if(t[t[rt].r].sz+t[rt].cnt>=k)return t[rt].v;
104     else return ask_rank(t[rt].l,k-t[t[rt].r].sz-t[rt].cnt);
105 }
106 void link(int u,int v){
107     u=find(u);v=find(v);
108     if(u==v)return;
109     if(t[u].sz<t[v].sz)swap(u,v);
110     Merge(rot[v],rot[u]);//v向u合并 
111     fa[v]=u;
112     return;
113 }
114 int n,m,Q;
115 int h[mxn],ans[mxn*5];
116 
117 void solve(){
118     int i,j;
119     srand(19260817);
120     for(i=1;i<=n;i++){
121         insert(h[i],1,rot[i]);
122     }//treap init 
123     int hd=1;
124     for(i=1;i<=Q;i++){
125         while(e[hd].w<=q[i].x && hd<=m){
126             link(e[hd].x,e[hd].y);
127             hd++;
128         }
129         int x=find(q[i].v);
130         int res=ask_rank(rot[x],q[i].k);
131         if(!res)ans[q[i].id]=-1;
132         else ans[q[i].id]=res;
133     }
134     return;
135 }
136 int main(){
137 //    freopen("Input.in","r",stdin);
138     int i,j;
139     n=read();m=read();Q=read();
140     for(i=1;i<=n;i++){
141         h[i]=read();
142         fa[i]=i;
143     }
144     for(i=1;i<=m;i++){
145         e[i].x=read();e[i].y=read();e[i].w=read();
146     }
147     for(i=1;i<=Q;i++){
148         q[i].v=read();q[i].x=read();q[i].k=read();q[i].id=i;
149     }
150     sort(e+1,e+m+1);
151     sort(q+1,q+Q+1);
152     solve();
153     for(i=1;i<=Q;i++){
154         printf("%d\n",ans[i]);
155     }
156     return 0;
157 }

 

Bzoj3545 [ONTAK2010]Peaks

标签:name   二叉树   div   memory   printf   改变   algorithm   swa   shu   

原文地址:http://www.cnblogs.com/SilverNebula/p/6657352.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!