首页 > 其他分享 >NOIP2023模拟2联测23 T2 害怕

NOIP2023模拟2联测23 T2 害怕

时间:2023-10-25 22:45:32浏览次数:31  
标签:ch 优先级 23 int 边权 T2 edge maxn 联测

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(" ");
}

标签:ch,优先级,23,int,边权,T2,edge,maxn,联测
From: https://www.cnblogs.com/binbinbjl/p/17788302.html

相关文章

  • 2023.10 做题纪要 #3
    目录2023.10.23P9755[CSP-S2023]种树ABC304ExConstrainedTopologicalSort2023.10.24AGC019EShuffleandSwapAGC017FZigzagCF1827EBusRoutes2023.10.25P8426[JOIOpen2022]放学路(SchoolRoad)P6790[SNOI2020]生成树P9333[JOISC2023Day2]Council2023.10.23CSP......
  • 2023 CSP-S 退役记
    DAY-2上午考了模拟赛,下午复习板子。后记:板子P用没有,都没用上。DAY-1上午拿到手机了哦哦哦在机房打引诱,之后去坐了大巴车。在大巴上把『想要成为影之实力者』第二季看了\(1\sim3\)集。等高铁的时候看见wjl再看间谍过家家,才知道出第二季了,然后在高铁上把间谍过家家第二......
  • 23.10.25(前端页面输入框的各种操作1)
    <tr><%--限制必须输入,学号限制位数、前四位必须是2023,性别限制男或女,专业用下拉框--%><th>姓名</th><inputtype="text"name="name"required><th>学号</th><inputtype="text"name="number"requ......
  • 23.10.25(前端页面输入框的各种操作2)
    <scripttype="text/javascript"><!--全选的方法--><--复选框的定义方法以及全选方法-->functionselectAll(){vars=document.getElementsByName("like");for(vari=0;......
  • jz2440-2023-10-25
    1、一般提到分析kernel的启动流程就要从strart.s入手,这是为什么?线索在哪里?因为烧录kernel时会使用到uImage,所以接下来去找uImage是如何生成的,通过源码顶层Makefile可以找到uImage是从vmlinux得到的,还是在该Makefile,可以找到vmlinux依赖于start.s。2、根据uboot的bootargs命令行参......
  • NOIP2023模拟2联测23 C. 负责
    NOIP2023模拟2联测23C.负责目录NOIP2023模拟2联测23C.负责题目大意思路code题目大意给你\(n\)个区间\([l_i,r_i]\),每个区间有个\(w_i\)。如果两个区间有交集(包括端点)那么两个区间就可以连边,形成一个图。现在需要你删除一些区间,使得每个区间大小不超过\(k\)。......
  • 2023.10.25——每日总结
    学习所花时间(包括上课):9h代码量(行):0行博客量(篇):1篇今天,上午学习,下午学习;我了解到的知识点:1.java断言,代码区域等明日计划:学习......
  • 76th 2023/10/10 Atcoder 10/8-ARC-T3
    这道题题目很有意思,看上去是很简单明显的计数,但一思考会发现要死很多重复状态因为标记的线很容易让人从一个方框开始思考起,所以很容易带入关于重复考虑的误区观察到线是斜着的,思考影响到的范围若涂上一个格子或左一个格子的右下,则该格子不能填涂左上观察到影响范围是一个个斜......
  • 75th 2023/10/6 k-D Tree
    附上一图:按维度分级,每次轮换用哪个维度即可oi中大多为2维这就是我对它的全部理解了结构与线段树几乎相同分左右结点时取当前区间段的中位数因而每一个节点都不同于线段树的表示范围它表示的是一个确确实实的节点的值访问前可以维护一个节点及它的子树的维度上下界以减少询......
  • 74th 2023/10/5 模拟赛总结56
    T1看完题目,看到n<=9的限制,心头一紧一个词汇浮现于心:BruceForces暴力+记忆化,\(O(能过)\)但赛时并没有这样打,而是选择了往DP方面思考因为真的没想到能过然后DP呢,又不清楚该如何存一列的状态就匆匆暴力后离去考虑状压DP保留有用状态关键点:\(k=\min(k,n-k)\)可以参考\(C^k......