NOIP2023模拟2联测23 T2 害怕

NOIP2023模拟2联测23 T2 害怕

好像写了一种出题人意料之外的算法。

思路

在生成树上加入白边,白边和若干条蓝色边形成环,环上的蓝色边必须要分配比该白色边更小的边权(最小生成树)。

给每一条边一个分配优先级,优先级的数越小,优先级越高,分配的边权越小。

一开始所有边的优先级的数都等于自己本身的输入顺序。

不断加入白边,与白边形成环的蓝边,优先级有一下两个选择:1.选自己的输入顺序;2.选白边的输入顺序。

每一条边都希望自己分配的边权更小,所以该边会上述选择较小者。

正确性证明:

如果蓝色边边权比白色边小:不做改动,依旧分配之前的边权。

如果蓝色边边权比白色边大:如果不做改动,那么白色边分配的边权要等到,形成环的蓝边边权在原优先级上分配结束,才能分配自己。那么可能会有优先级比白边低的边分配到比白色边更小的值,这肯定是不优的(白色边排序更靠前,边权越低,带来字典序越小)。

这里也可以距离证明一下,正确性是有保证的。

那么维护两点之间路径边的优先级即可,为了方便实现,可以边权压点权,使用树剖。

树剖的线段树维护的是该段内的优先级的分配情况,发现如果从小到大枚举白色边形成环,那么所有的蓝色边的优先级最多被更改一次(或者说只被白色边找到一次,因为后面找到这条蓝边的优先级肯定没有之前的高)。

维护两点路径可以看做求 LCA

不过线段树后面被卡时限了,发现求 LCA 是若干个完整的链加三四个分裂的链,完整的链实际上查过一次就不用查了,可以大大优化复杂度。

线段树实现:

#include<bits/stdc++.h>
using namespace std;

#define fi first
#define se second

const int maxn=5e5+5;

struct node1
{
    int to,nxt,id;
}edge[maxn*2];
struct node2
{
    int u,v,id;
}ed[maxn];

int n,m,tot,cnt,cok,ct,cdq;
int head[maxn],hso[maxn],sz[maxn],p[maxn],fp[maxn],fa[maxn],top[maxn],ans[maxn],deep[maxn],cis[maxn];

bool vis[maxn];

pair<int,int>dq[maxn];

vector< pair<int,int> >vec[maxn];

inline int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}
inline void write(int X)
{
    if(X<0) {X=~(X-1); putchar('-');}
    if(X>9) write(X/10);
    putchar(X%10+'0');
}

inline void add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].nxt=head[x];
    edge[tot].id=z;
    head[x]=tot;
}

inline void dfs1(int u)
{
    sz[u]++;
    for(int i=head[u];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa[u]) continue;
        fa[v]=u;
        deep[v]=deep[u]+1;
        cis[v]=edge[i].id;
        dfs1(v);
        sz[u]+=sz[v];
        if(sz[v]>sz[hso[u]]) hso[u]=v;
    }
    return ;
}
inline void dfs2(int u,int tp)
{
    if(!u) return ;
    p[u]=++cok;
    fp[cok]=u;
    top[u]=tp;
    dfs2(hso[u],tp);
    for(int i=head[u];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa[u]||v==hso[u]) continue;
        dfs2(v,v);
    }
    return ;
}

inline void lca(int x,int y,int t)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        vec[p[top[x]]].push_back(make_pair(t,p[x]));
        x=fa[top[x]];
    }
    if(deep[x]<deep[y]) swap(x,y);
    vec[p[y]+1].push_back(make_pair(t,p[x]));
    return ;
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x,y,op;
        x=read(),y=read(),op=read();
        if(op) add(x,y,i),add(y,x,i);
        else
        {
            cnt++;
            ed[cnt].u=x;
            ed[cnt].v=y;
            ed[cnt].id=i;
        }
    }

    deep[1]=1;
    dfs1(1);
    dfs2(1,1);

    for(int i=1;i<=cnt;i++)
        lca(ed[i].u,ed[i].v,ed[i].id);

    priority_queue< pair<int,int> ,vector< pair<int,int> > , greater< pair<int,int> > >tq;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<vec[i].size();j++)
        {
            if(!tq.empty())
            {
                if(tq.top().first<vec[i][j].first&&tq.top().second>=vec[i][j].second) continue;
            }
            tq.push(vec[i][j]);
        }
        if(tq.empty())
        {
            dq[++cdq]=make_pair(cis[fp[i]],cis[fp[i]]);
        }
        else
        {
            while(!tq.empty())
            {
                if(tq.top().second<i) tq.pop();
                else break;
            }
            if(tq.empty()) dq[++cdq]=make_pair(cis[fp[i]],cis[fp[i]]);
            else dq[++cdq]=make_pair(min(cis[fp[i]],tq.top().first),cis[fp[i]]);
        }
    }
    for(int i=1;i<=cnt;i++) dq[++cdq]=make_pair(ed[i].id,m+1);

    sort(dq+1,dq+cdq+1);
    for(int i=1;i<=cdq;i++)
    {
        if(dq[i].se==0) continue;
        ct++;
        int k=dq[i].se;
        if(k==m+1) k=dq[i].fi;
        ans[k]=ct;
    }
    for(int i=1;i<=m;i++) write(ans[i]),printf(" ");
}
posted @   彬彬冰激凌  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示