[主席树 Kruscal] BZOJ 3545 [ONTAK2010]Peaks & 3551 [ONTAK2010]Peaks加强版

30 篇文章 0 订阅
21 篇文章 0 订阅

Orz hzwer

据出题人的做法。。。

就是做最小生成树,但合并两结点x,y的时新建结点ext,把ext连向fa(x),fa(y)这样建出一棵树,ext的权为该边的边权

找一个点v不超过x的子树的根,可以用倍增,以它为根的子树就是v不超过x所能到达的连通块

dfs+主席树就行了。。


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define V G[p].v
using namespace std;
 
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
    return *p1++;
}
 
inline void read(int &x)
{
    char c=nc(),b=1;
    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
 
const int N=200005,K=21;
 
int sx[N],icnt;
inline int Bin(int x){
    return lower_bound(sx+1,sx+icnt+1,x)-sx;
}
 
namespace SSeg{
    const int M=5000005;
    int ncnt;
    int root[N];
    int ls[M],rs[M],sum[M];
    inline void Add(int &x,int y,int l,int r,int t)
    {
        if (!x) x=++ncnt; int mid=(l+r)>>1;
        if (l==r){
            sum[x]=sum[y]+1; return;
        }
        if (t<=mid)
            Add(ls[x],ls[y],l,mid,t),rs[x]=rs[y];
        else
            Add(rs[x],rs[y],mid+1,r,t),ls[x]=ls[y];
        sum[x]=sum[ls[x]]+sum[rs[x]];
    }
     
    inline int Query(int x,int y,int l,int r,int k)
    {
        if (l==r) 
        {
            if (sum[y]-sum[x]>=k) return l;
            return -1;
        }
        int mid=(l+r)>>1,tem=sum[rs[y]]-sum[rs[x]];
        if (k>tem)
            return Query(ls[x],ls[y],l,mid,k-tem);
        else
            return Query(rs[x],rs[y],mid+1,r,k);
    }
}
 
struct edge{
    int u,v,next;
}G[N<<1];
int head[N],inum;
 
inline void add(int u,int v,int p)
{
    G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
 
int wgt[N],val[N];
int tid[N],size[N],clk;
int fat[N][K],maxv[N][K];
 
inline void dfs(int u,int fa){
    using namespace SSeg;
    fat[u][0]=fa; maxv[u][0]=wgt[fa]; tid[u]=++clk; size[u]=1;
    for (int k=1;k<K;k++) fat[u][k]=fat[fat[u][k-1]][k-1],maxv[u][k]=max(maxv[u][k-1],maxv[fat[u][k-1]][k-1]);
    if (val[u])
        Add(root[clk],root[clk-1],1,icnt,val[u]);
    else
        root[clk]=root[clk-1];
    for (int p=head[u];p;p=G[p].next)
        dfs(V,u),size[u]+=size[V];
}
 
inline int LCA(int u,int v){
    for (int k=K-1;~k;k--)
        if (maxv[u][k]<=v)
            u=fat[u][k];
    return u;
}
 
namespace TSet{
    int fat[N],rank[N];
    inline void init(int n){
        for (int i=1;i<=n;i++) fat[i]=i;
    }
    inline int Fat(int u){
        return fat[u]==u?u:fat[u]=Fat(fat[u]);
    }
}
 
int n,m;
 
struct edges{
    int u,v,w;
    bool operator < (const edges &B) const{
        return w<B.w;
    }
}D[500005];
 
int pcnt;
 
inline void Krus(){
    sort(D+1,D+m+1);
    TSet::init(n<<1); pcnt=n;
    int x,y,fx,fy;
    for (int i=1;i<=m;i++)
    {
        x=D[i].u; y=D[i].v;
        fx=TSet::Fat(x); fy=TSet::Fat(y);
        if (fx==fy) continue;
        ++pcnt;
        TSet::fat[fx]=pcnt; add(pcnt,fx,++inum);
        TSet::fat[fy]=pcnt; add(pcnt,fy,++inum); 
        wgt[pcnt]=D[i].w;
    }
    wgt[0]=1<<30; dfs(pcnt,0);
}
 
int lastans;
 
inline void Solve(){
    using namespace SSeg;
    int u,v,k;
    read(u); read(v); read(k); u^=lastans; v^=lastans; k^=lastans;
    int lca=LCA(u,v);
    int ret=Query(root[tid[lca]-1],root[tid[lca]+size[lca]-1],1,icnt,k);
    if (ret==-1)
        printf("-1\n"),lastans=0;
    else
        printf("%d\n",lastans=sx[ret]);
}
 
int main()
{
    int Q;  read(n); read(m); read(Q);
    for (int i=1;i<=n;i++) read(val[i]),sx[++icnt]=val[i];
    sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
    for (int i=1;i<=n;i++) val[i]=Bin(val[i]);
    for (int i=1;i<=m;i++)
        read(D[i].u),read(D[i].v),read(D[i].w);
    Krus();
    while (Q--)
        Solve();
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值