牛客练习赛62 E水灾(树剖求lca,kruscal重构树)

题目链接:https://ac.nowcoder.com/acm/contest/5205/E

思路:这题真的是,卡常卡的我怀疑人生,但也因此也优化了一下lca的板子,这波血赚

询问要求的是询问点两两之间不可达的最小水位,相当于选取一个数x,把比x小的边全删了,那么很容易想把这张图转化为一颗最大生成树,如果在最大生成树上不可达了,那么在原图上显然不可达。

在树上的话,如果可以离线,那么点分乱搞可能也行?没细想,纯属口胡

这题要求强制在线,那么就需要用到kruscal重构树了(..这玩意就不讲了),想练手的也可以做做 Contest #11 D

这题用到了kruscal重构树的几条性质

1.(只考虑新节点)根据以下的构造过程,kruskal重构树是一颗二叉树,并符合二叉堆的性质。

2.kruskal的每个子树是原图上保留边权不小于根节点权值的边后的极大连通子图。

根据性质2,可以将题目转化为选择一个权值,删除比这个权值小的点,使得询问点两两不可达,接着根据性质1最大生成树的kruscal重构树是满足小根堆的性质,那么如果两个点可达,我们删掉它们的lca显然是最优的

我们先想想对于每个询问暴力怎么做,你可以暴力枚举两个询问点求得它们lca的权值,然后对所有权值取个max,但这显然会超时,不过由于这棵树满足小根堆的性质,只需要枚举树上相邻两个询问点的lca就行了,因为如果不是相邻的点,它们求得的lca权值显然更小。

这份是带优化的倍增求lca的

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-6
#define lc d<<1
#define rc d<<1|1
#define Pll pair
#define P pair
#define pi acos(-1)
const int N=1e6+8;
int tot,n,m,x,y,q,k,zz,qw,ans,lans,d[N],qu[N];
int fa[N][22],id[N],val[N],deep[N],head[N],lg[N];
struct as{
int u,v,d;}a[N],e[N];
bool cmp1(as a,as b) {return a.d>b.d;}
bool cmp(int a,int b) {return id[a]deep[y]) x=fa[x][lg[deep[x]-deep[y]]-1];
    if(x==y)  return x;
    FOL(i,lg[deep[x]]-1,0)
     if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m>>q;
    FOR(i,1,2*n+1)
     lg[i]=lg[i-1]+(1<

这份是树剖求的

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-6
#define lc d<<1
#define rc d<<1|1
#define Pll pair
#define P pair
#define pi acos(-1)
const int N=1e6+8;
int tot,n,m,x,y,q,k,zz,qw,ans,lans,sz[N],qu[N];
int fa[N],id[N],val[N],deep[N],head[N],son[N],top[N];
struct as{
int u,v,d;}a[N],e[N];
bool cmp1(as a,as b) {return a.d>b.d;}
bool cmp(int a,int b) {return id[a]maxson) son[u]=v,maxson=sz[v];
    }
}
void dfs1(int u,int tfa)
{
    top[u]=tfa;
    if(!son[u]) return;
    dfs1(son[u],tfa);
    for(int i=head[u];i!=-1;i=e[i].u)
    {
        int v=e[i].v;
        if(v==son[u]) continue;
        dfs1(v,v);
    }
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]>=deep[top[y]]) x=fa[top[x]];
        else y=fa[top[y]];
    }
    return deep[x]>n>>m>>q;
    qw=n;REW(head,-1);
    FOR(i,1,2*n-1) fa[i]=i;
    FOR(i,1,m) a[i].u=read(),a[i].v=read(),a[i].d=read();
    sort(a+1,a+m+1,cmp1);
    FOR(i,1,m)
    {
        int fx=fid(a[i].u),fy=fid(a[i].v);
        if(fx==fy) continue;
        fa[fx]=fa[fy]=++qw;
        val[qw]=a[i].d;
        add(qw,fx),add(qw,fy);
        if(qw==2*n-1) break;
    }
    dfs(qw,0),dfs1(qw,0);
    while(q--)
    {
        k=read();ans=0;
        FOR(i,1,k) qu[i]=read(),qu[i]^=lans;
        sort(qu+1,qu+k+1,cmp);
        FOR(i,2,k) ans=max(ans,val[lca(qu[i],qu[i-1])]);
        printf("%d\n",ans);
        lans=ans;
    }
    return 0;
}

 

你可能感兴趣的:(牛客练习赛62 E水灾(树剖求lca,kruscal重构树))