标签:first operator event val pen ufs har 重构 for
给一个图,每个点有点权,$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; } }
标签:first operator event val pen ufs har 重构 for
原文地址:https://www.cnblogs.com/Kong-Ruo/p/9852786.html