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 重构树,每次能走的是一个子树

于是我们可以先倍增找到能走的最高的点(倍增找到重构树上点权小于等于 $y$ 的最高的点)

之后就变成了“一个子树里第 $k$ 小的点权是多少”

我们把 dfs 序处理出来,就是一个区间第 $k$ 小

注意重构树上的 dfs 序要特殊处理一下

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 2e5 + 10;
int n,m,q,lastans,ToT,nd;
int first[maxn],to[maxn << 1],nx[maxn << 1],val[maxn],cnt;
inline void add(int u,int v)
{
    to[++cnt] = v;
    nx[cnt] = first[u];
    first[u] = cnt;
    to[++cnt] = u;
    nx[cnt] = first[v];
    first[v] = cnt;
}
struct EDG{int u,v,w;bool operator < (const EDG &b)const{return w < b.w;}}es[maxn * 10];
int tp;
int h[maxn],rnk[maxn];
int ufs[maxn];
inline int find(int x){return x == ufs[x] ? x : ufs[x] = find(ufs[x]);}
int mn[maxn],mx[maxn],dfn,fa[maxn][23],reh[maxn];
void dfs(int x)
{
    //cout<<x<<" ";
    if(x <= n) mn[x] = mx[x] = ++dfn,reh[dfn] = x;
    else mn[x] = n + 1;
    for(int i=1;i<=20;i++)fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int i=first[x];i;i=nx[i])
    {
        if(to[i] == fa[x][0])continue;
        fa[to[i]][0] = x;
        dfs(to[i]);
        mn[x] = min(mn[x],mn[to[i]]);
        mx[x] = max(mx[x],mx[to[i]]);
    }
}
inline int get_val(int x,int w)
{
    for(int i=20;~i;i--)
        if(fa[x][i] && h[fa[x][i]] <= w)x = fa[x][i];
    return x;
}
int root[maxn],ls[maxn * 10],rs[maxn * 10],sum[maxn * 10],TaT;
inline void Insert(int &now,int pre,int l,int r,int pos)
{
    now = ++TaT;
    ls[now] = ls[pre];rs[now] = rs[pre];
    sum[now] = sum[pre] + 1;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(pos <= mid)Insert(ls[now],ls[pre],l,mid,pos);
    else Insert(rs[now],rs[pre],mid + 1,r,pos);
}
inline int query(int now,int pre,int l,int r,int k)
{
    //cout<<now<<" "<<pre<<" "<<l<<" "<<r<<" "<<" "<<k<<endl;
    if(sum[now] - sum[pre] < k)return -1;
    if(l == r) return l;
    int mid = (l + r) >> 1;
    if(sum[rs[now]] - sum[rs[pre]] >= k)return query(rs[now],rs[pre],mid + 1,r,k);
    else return query(ls[now],ls[pre],l,mid,k - sum[rs[now]] + sum[rs[pre]]);
}
int main()
{
    //freopen("szc10e.in","r",stdin);
    //freopen("fc.out","w",stdout); 
    n = read(),m = read(),q = read();
    for(int i=1;i<=n;i++)rnk[i] = h[i] = read();
    for(int i=1;i<=n + n;i++)ufs[i] = i;
    sort(rnk + 1,rnk + n + 1);
    ToT = unique(rnk + 1,rnk + n + 1) - rnk - 1;
    for(int i=1;i<=n;i++)h[i] = lower_bound(rnk + 1,rnk + ToT + 1,h[i]) - rnk;
    for(int i=1;i<=m;i++)
    {
        int u = read(),v = read(),w = read();es[i] = (EDG){u,v,w};
    }nd = n;/*system("cls");*/sort(es + 1,es + m + 1);
    int fu,fv;
    for(int i=1;i<=m;i++)
    {
        fu = find(es[i].u),fv = find(es[i].v);
        if(fu == fv)continue;
        ++nd;h[nd] = es[i].w;
        add(nd,fu);add(nd,fv);
        ufs[fu] = ufs[fv] = nd;
    }
    //system("pause");
    dfs(nd);
    for(int i=1;i<=n;i++)
    {
        Insert(root[i],root[i - 1],1,n,h[reh[i]]);
    }
    int v,x,k,rt;
    while(q--)
    {
        v = read(),x = read(),k = read();
        if(lastans != -1)v ^= lastans,x ^= lastans,k ^= lastans;
        rt = get_val(v,x);
        lastans = query(root[mx[rt]],root[mn[rt] - 1],1,n,k);
        if(lastans != -1)lastans = rnk[lastans];
        printf("%d\n",lastans);
       // lastans = 0;
    }
}
View Code

 

posted @ 2018-10-25 20:49  探险家Mr.H  阅读(140)  评论(0编辑  收藏  举报