BZOJ 3545: [ONTAK2010]Peaks 启发式合并 + 离线 + Splay

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

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

有小于等于 $x$ 这个条件十分不好办 .

考虑离线,按照 $x$ 从小到大依次加入,查询的时候直接在 $splay$ 中查询第 $k$ 大即可. 

#include <cstdio>
#include <algorithm>  
#include <stack>   
#define N 600005  
#define inf 1000000002 
#define setIO(s) freopen(s".in","r",stdin)  , freopen(s".out","w",stdout)    
using namespace std;  
int splay_cnt;      
namespace IO 
{   
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() 
    {
        int x=0; 
        char c=nc(); 
        while(c<48) c=nc(); 
        while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); 
        return x;
    }
}; 
struct Edge 
{ 
    int u , v , c ;  
}ed[N]; 
bool cmp(Edge a, Edge b) 
{
    return a.c < b.c; 
}  
struct Ask 
{ 
    int u , x , k , id ; 
}as[N]; 
bool cmp2(Ask a, Ask b) 
{
    return a.x < b.x;      
} 
#define lson ch[x][0] 
#define rson ch[x][1]  
stack <int> S; 
int answer[N], h[N], size[N], f[N], ch[N][2], siz[N], val[N], rt[N], p[N], mk = 0;           
inline void init(int sz) 
{
    for(int i = 1; i <= sz ; ++i) S.push(i);   
    for(int i = 1; i <= sz ; ++i) p[i] = i, size[i] = 1; 
} 
int find(int x) 
{
    return p[x] == x ? x : p[x] = find(p[x]); 
} 
inline int newnode() 
{
    int u = S.top();  S.pop(); 
    return u;       
}
inline int get(int x) 
{
    return ch[f[x]][1] == x; 
}  
inline void pushup(int x) 
{
    siz[x] = siz[lson] + siz[rson] + 1;    
}
inline void rotate(int x) 
{
    int old = f[x], fold = f[old], which = get(x); 
    ch[old][which] = ch[x][which ^ 1], f[ch[old][which]] = old;  
    ch[x][which ^ 1] = old, f[old] = x, f[x] = fold; 
    if(fold) ch[fold][ch[fold][1] == old] = x;        
    pushup(old), pushup(x);        
} 
inline void splay(int x, int &tar) 
{ 
    int u = f[tar]; 
    for(int fa; (fa = f[x]) ^ u; rotate(x)) 
        if(f[fa] ^ u) 
            rotate(get(fa) == get(x) ? fa : x);   
    tar = x;     
}
inline int kth(int x, int k) 
{ 
    if(siz[x] < k) return inf;  
    while(1) 
    {   
        if(k > siz[rson]) 
        {
            k -= (siz[rson] + 1);        
            if(!k) return x;          
            else x = lson;      
        }
        else x = rson;    
    }
}
inline void insert(int &x, int ff, int v) 
{
    if(!x) 
    {
        mk = x = newnode();        
        f[x] = ff, val[x] = v, pushup(x);       
        return; 
    }     
    insert(ch[x][v > val[x]], x, v), pushup(x); 
}     
inline void DFS(int y, int x) 
{       
    if(lson) DFS(y, lson); 
    if(rson) DFS(y, rson);      
    int v = val[x];   
    S.push(x), val[x] = siz[x] = lson = rson = f[x] = 0, insert(rt[y], 0, v), ++splay_cnt;  
    if(splay_cnt % 6 == 0) splay(mk, rt[y]);         
}   
inline void connect(int o) 
{
    int u = ed[o].u, v = ed[o].v;   
    int x = find(u), y = find(v);   
    if(x ^ y) 
    { 
        if(size[y] < size[x]) swap(x, y);    
        p[x] = y, size[y] += size[x], DFS(y, rt[x]);                
    }
}
int main() 
{
    using namespace IO; 
    // setIO("input"); 
    int n, m, q, i, j;   
    n = rd(), m = rd(), q = rd(), init(n);  
    for(i = 1; i <= n ; ++i) h[i] = rd(), insert(rt[i], 0, h[i]);           
    for(i = 1; i <= m ; ++i) ed[i].u = rd(), ed[i].v = rd(), ed[i].c = rd();        
    sort(ed + 1, ed + 1 + m, cmp);      
    for(i = 1; i <= q ; ++i) 
    {
        as[i].u = rd(), as[i].x = rd(), as[i].k = rd(), as[i].id = i; 
    }
    sort(as + 1, as + 1 + q, cmp2);           
    for(i = j = 1; i <= q; ++i) 
    {
        while(ed[j].c <= as[i].x && j <= m) connect(j), ++j; 
        int l = kth(rt[find(as[i].u)], as[i].k);            
        answer[as[i].id] = (l == inf ? inf : val[l]);   
        if(l ^ inf) 
        {
            ++splay_cnt; 
            if(splay_cnt % 6 == 0) splay(l, rt[find(as[i].u)]);
        }      
    }
    for(i = 1; i <= q; ++i) printf("%d\n",answer[i] == inf ? -1 : answer[i]);  
    return 0; 
}

  

posted @ 2019-08-10 11:25  EM-LGH  阅读(203)  评论(0编辑  收藏  举报