牛客練習賽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 <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
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<ll,ll>
#define P pair<int,int>
#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]<id[b];}
int fid(int x)
{
    int a=x,b;
    while(fa[a][0]!=a) a=fa[a][0];
    while(x!=a) b=fa[x][0],fa[x][0]=a,x=b;
    return a;
}
void add(int u,int v)
{
    e[tot].u=head[u];
    e[tot].v=v;
    head[u]=tot++;
}
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
void dfs(int u,int f)
{
    id[u]=++zz;deep[u]=deep[f]+1;fa[u][0]=f;d[zz]=u;
    FOR(i,1,lg[deep[u]])
     fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int i=head[u];i!=-1;i=e[i].u) dfs(e[i].v,u);
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])  swap(x,y);
    int d=deep[x]-deep[y];
    while(deep[x]>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<<lg[i-1]==i);
    qw=n;REW(head,-1);
    FOR(i,1,2*n-1) fa[i][0]=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][0]=fa[fy][0]=++qw;
        val[qw]=a[i].d;
        add(qw,fx),add(qw,fy);
        if(qw==2*n-1) break;
    }
    dfs(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;
}

這份是樹剖求的

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
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<ll,ll>
#define P pair<int,int>
#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]<id[b];}
int fid(int x)
{
    int a=x,b;
    while(fa[a]!=a) a=fa[a];
    while(x!=a) b=fa[x],fa[x]=a,x=b;
    return a;
}
void add(int u,int v)
{
    e[tot].u=head[u];
    e[tot].v=v;
    head[u]=tot++;
}
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
void dfs(int u,int f)
{
    sz[u]=1,id[u]=++zz;
    deep[u]=deep[f]+1;fa[u]=f;
    int maxson=0;
    for(int i=head[u];i!=-1;i=e[i].u)
    {
        int v=e[i].v;
        dfs(v,u);
        sz[u]+=sz[v];
        if(sz[v]>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]<deep[y]?x:y;
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    cin>>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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章