[2017纪中11-9]玩游戏 最短路数+LCA

题面
考虑这样定义的最短路对应的最短路树恰好是最小生成树。因为add操作不多,每次暴力重构最短路树,询问的时候跑lca即可。复杂度O(n^2logn)。
代码:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int n,m,K,Q,fa[5010],d[5010],f[5010][15];
ll g[5010][15];
struct edge
{
    int t;ll w;
    edge *next;
}*con[5010];
void ins(int x,int y,ll w)
{
    edge *p=new edge;
    p->t=y;
    p->w=w;
    p->next=con[x];
    con[x]=p;
}
struct node
{
    int x,y;ll w;
}e[110000],z[5010];
bool cmp(node a,node b){return a.w<b.w;}
int getfa(int v)
{
    if(fa[v]==v) return v;
    fa[v]=getfa(fa[v]);
    return fa[v];
}
bool merge(int x,int y)
{
    if(getfa(x)!=getfa(y)) {fa[fa[x]]=y;return 1;}
    return 0;
}
void MST(int &m)
{
    for(int i=1;i<=n;i++)
        fa[i]=i;
    sort(e+1,e+m+1,cmp);
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        if(merge(e[i].x,e[i].y)) z[++cnt]=e[i];
        if(cnt==n-1) break;
    }
    for(int i=1;i<n;i++)
        e[i]=z[i];
    m=n-1;  
}
void dfs(int v)
{
    d[v]=d[f[v][0]]+1;
    for(edge *p=con[v];p;p=p->next)
        if(p->t!=f[v][0])
        {
            f[p->t][0]=v;
            g[p->t][0]=p->w;
            dfs(p->t); 
        }
}
void pre()
{
    for(int k=1;(1<<k)<=n;k++)
        for(int i=1;i<=n;i++)
            f[i][k]=f[f[i][k-1]][k-1],g[i][k]=max(g[i][k-1],g[f[i][k-1]][k-1]);
}
ll qry(int x,int y)
{
    ll re=0;
    if(d[x]<d[y]) swap(x,y);
    for(int k=14;k>=0;k--) if(d[f[x][k]]>=d[y]) re=max(re,g[x][k]),x=f[x][k];
    if(x==y) return re;
    for(int k=14;k>=0;k--) if(f[x][k]!=f[y][k]) re=max(re,max(g[x][k],g[y][k])),x=f[x][k],y=f[y][k];
    return max(re,max(g[x][0],g[y][0]));
}
int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=m;i++)
        scanf("%d%d%lld",&e[i].x,&e[i].y,&e[i].w);
    scanf("%d",&Q);
    bool mi=1;
    while(Q--)
    {
        char opt[6];int x,y;scanf("%s",opt);
        if(opt[0]=='g')
        {
            if(mi)
            {
                MST(m);
                for(int i=1;i<=n;i++)con[i]=NULL;
                memset(f,0,sizeof(f));
                memset(g,0,sizeof(g));
                memset(d,0,sizeof(d));
                for(int i=1;i<=m;i++)
                    ins(e[i].x,e[i].y,e[i].w),ins(e[i].y,e[i].x,e[i].w);
                dfs(1);
                pre();
                mi=0;
            }
            ll ans=0;
            for(int i=1;i<=K;i++)
            {
                scanf("%d%d",&x,&y);
                ans^=qry(x,y);
            }
            if(ans==0) puts("Baozika");
            else puts("madoka");
        }
        else {m++;mi=1;scanf("%d%d%lld",&e[m].x,&e[m].y,&e[m].w);}
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值