首页 > 其他分享 >图论口胡记录

图论口胡记录

时间:2023-08-16 10:44:23浏览次数:43  
标签:连边 图论 子树 记录 int 短路 len 复杂度

图论口胡记录

Xor-MST

\(Borvuka\)算法版题

\(Borvuka\)的流程是每次对于每个联通块中都找到一条向外部最小的边,然后再将边相连的两个连通块合并。可以发现每次连通块的个数都会减半,只会合并\(\log_n\)次,那么中间找最小边的过程中,对于没有显式建边的题目我们就可以用数据结构维护求出最小边。总时间复杂度为\(O(n\log_n\times DS)\)。

对于这道题,我们考虑用\(0-1trie\)快速计算异或最小值。记合并过程中同一个连通块的点同色,那么可以先将所有节点值加入\(trie\)中,当找某个连通块向外的最小边时就将\(trie\)中所有该种颜色的点删除查最值,然后再插回去即可。复杂度\(O(n log_n^2)\)。

ll boruvka(){
    dsu.init(n);
    for (int i=1;i<=n;i++){
        col[i]=i;
        t.insert(a[i],1,i);
    }
    cnt=0;ans=0;
    while(cnt<n-1){
        for (int i=1;i<=n;i++) v[i].clear();
        for (int i=1;i<=n;i++){
            v[col[i]].push_back(i);
        }
        for (int i=1;i<=n;i++){
            if (v[i].size()){
                mn[i]=0x3f3f3f3f;
                for (const auto &x:v[i]) t.insert(a[x],-1,x);
                for (const auto &x:v[i]){
                    pair <int,int> p=t.query(a[x]);
                    if (p.first<mn[i]){
                        out[i]=make_pair(x,p.second);
                        mn[i]=p.first;
                    }
                }
                for (const auto &x:v[i]) t.insert(a[x],1,x);
            }
        }
        for (int i=1;i<=n;i++){
            if (v[i].size()){
                int u=out[i].first,v=out[i].second;
                int X=dsu.find(u),Y=dsu.find(v);
                if (X==Y) continue;
                if (dsu.siz[X]>dsu.siz[Y]) swap(X,Y);
                cnt++;ans+=a[u]^a[v];
                dsu.fa[X]=Y;dsu.siz[Y]+=dsu.siz[X];
            }
        }
        for (int i=1;i<=n;i++) col[i]=dsu.find(i);
    }
    return ans;
}

Tree MST这道题也可以用\(Brovuka\)做。

P3645 [APIO2015] 雅加达的摩天楼

有一个很明显的暴力:对于每个节点每次向左/右跳到达的点连边,跑一遍\(b_0-b_1\)的最短路就是答案。

考虑优化这个算法,可以想到每个点只向\(b_i-p_i\),\(b_i+p_i\)连边。然而无法保证正确性,因为中间办法更换\(doge\),只能建n张子图,每个点都向左右\(i\)的位置连边,空间时间都吃不消。

又因为类比弹飞绵羊当步长比较大时,暴力跳复杂度是正确的,所以考虑根号分治。设分治阀域为\(len\),建出\(1-len\)的子图。对于\(p_i\)大于\(len\)的点直接暴力连边,小于\(len\)的点将其与\(p_i\)的子图上对应节点连边再跑最短路即可。

    for (int i=1;i<=len;i++){
        for (int j=1;j<=n;j++){
            if (j-i>=1) add(n+(i-1)*n+j,n+(i-1)*n+j-i,1);
            if (j+i<=n) add(n+(i-1)*n+j,n+(i-1)*n+j+i,1);
            add(n+(i-1)*n+j,j,0);
        }
    }
    for (int i=1;i<=n;i++){
        for (const auto &x:vec[i]){
            if (p[x]>len){
                for (int j=i-p[x],stp=1;j>=1;j-=p[x],stp++) add(i,j,stp);
                for (int j=i+p[x],stp=1;j<=n;j+=p[x],stp++) add(i,j,stp);
            }
            else add(i,n+(p[x]-1)*n+i,0);
        }
    }

分析\(len\)取何值时复杂度最优,子图会建\(3*len*n\)条边,暴力会连\(\frac{n^2}{len}\)条边,由均值有当\(len\)取\(\sqrt{\frac{n}{3}}\)时最优。

Dynamic Shortest Path

每次暴力更新后重新跑最短路复杂度\(O(qnlogm)\)比较接近时间限制,考虑优化使得每次不重跑最短路将\(log\)优化掉。

首先第一次\(dij\)跑出最短路后,先暴力将每条更新边加一,再记录下每个点最短路的改变量\(delta_i\),显然有\(delta_i<=min(n-1,v)\),因此考虑类似于最短路的松弛操作,开\(min(n-1,v)\)个\(queue\)记录\(delta_i\),每次取出一个节点\(x\),用\(dis[x]-dis[y]+w'+delta[x]\)(即当前节点改变量和前驱传过来的变化量之和)最小值尝试更新邻接点\(delta\)。最后再将每个节点\(dis\)加上\(delta_i\)即可。

for (int i=1;i<=n;i++) delta[i]=1e9;
for (int i=1;i<=v;i++){
    int x;read(x);
    E[x].w++;
}
delta[1]=0;vec[0].push(1);
for (int i=0;i<=min(n-1,v);i++){
    while(vec[i].size()){
        int x=vec[i].front();vec[i].pop();
        if (delta[x]!=i) continue;
        for (int j=head[x];j;j=E[j].nxt){
            int y=E[j].to,w=E[j].w;
            int tmp=w+dis[x]-dis[y]+delta[x];
            if (tmp<delta[y]&&tmp<=min(n-1,v)){
                delta[y]=tmp;
                vec[tmp].push(y);
            }
        }
    }
}
for (int i=1;i<=n;i++){
    if (delta[i]!=1e9) dis[i]+=delta[i];
}

CF1473E Minimum Path

妙妙题。

有一个比较显然的暴力是对于每个节点都用\(m^2\)个状态,即设\(dis(u,l,r)\)为在\(u\)点进过边权最小为\(l\),最大为\(r\)时的最短路,直接跑\(dij\)。

但是这样会有很多冗余的状态,考虑优化。先思考一个弱化的问题:求免费和加倍的边权在这条路径上任意分别取一条的最短路。显然这两条边一定分别是最大边和最小边,因此这个问题和原问题是等价的,这就是这道题比较神仙的思想。

那么接下来考虑对等价问题设计优化的状态,设\(dis(u,0/1,0/1)\)为到\(u\)且最大/最小边选/未选的最短路长度。讨论同状态之间和从0变为1的转移即可,比较简单,不再赘述。这玩意的本质是拆点。

注意最后的答案是\(min(dis[i][1][1],dis[i][0][0])\) (因为可能有只走一条边的情况,但是在等价问题中这条边会被选两次)

跳蚤王国的宰相

首先可以求出原树的重心\(C\)。

考虑对于每个不为\(C\)的节点\(x\)计算答案,发现从\(x->C\)的路径是这样的。

由于\(C\)是重心,所以\(x\)子树一定大小之和小于\(n/2\),只需要考虑将图中的一部分边断开接到\(x\)下边。

显然这样的边不可能在\(x->C\)的路径上,因为C子树大小大于等于\(n/2\),因此只能在\(C\)子树内。

考虑将\(C\)所有儿子按子树大小排序,每次贪心地选取子树大小最大,正确性显然。

然后讨论割完后\(x->C\)的路径节点数+\(C\)剩余子树大小\(\leq\) \(n/2\)已经满足条件,和\(C\)剩余子树大小\(\leq\) \(n/2\)后再多割一刀将\(C\)整棵子树割下来到\(x\)上两种情况。

实现上前缀和加二分即可。

    for (int i=1;i<=n;i++){
        if (i==rt){puts("0");continue;}
        int s=n-siz[bel[i]],delta=s-n/2;
        if (delta==0) {puts("0");continue;}
        int L=0,R=(int)vec.size()-1,p=-1,P;
        while(L<=R){
            int mid=(L+R)>>1;
            int cur=sum[mid];
            if (mid>=pos[bel[i]]) cur-=siz[bel[i]];
            if (n-siz[i]-cur<=n/2) P=mid,p=mid,R=mid-1;
            else if (s-cur<=n/2) P=mid,p=mid+1,R=mid-1;
            else L=mid+1;
        }
        if (P>=pos[bel[i]]) p--;
        printf("%d\n",p+1);
    }

标签:连边,图论,子树,记录,int,短路,len,复杂度
From: https://www.cnblogs.com/cqbzlzh/p/17633367.html

相关文章

  • ThingsKit物联网平台告警中心之上下线记录
    设备上下线功能用于监控设备的连接状态,当设备离线或下线时,系统会及时发出通知,以便用户能够及时处理。处理和详情处理设备上下线记录和查看设备上下线记录详情。搜索记录多条件筛选查看设备上下线记录。删除单项或批量删除设备上下线记录。文章来源(首发地址):ThingsKit物联......
  • ThingsKit物联网平台消息记录管理
    短信发送和邮件发送记录用户配置消息模板和消息配置后所有发送的邮件和短信的汇总,可点击查看详细信息。:::info......
  • 图论之存图-----邻接矩阵
    跟着思路敲了一遍,感觉清晰多了,但是还得多复习。就是利用了深度搜索,很奇妙。点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=2e5+10;intw[N][N];intvis[N];intn,m;inta,b,c;voiddfs(intu){ vis[u]=true; if(vis[u]){ for(inti=1;i<=......
  • [刺客伍六七&黑客] 魔刀千刃诞生与维护记录
    魔刀千刃的特写诞生之日:2023.7.29上传至pip源之日:2023.8.15此后会在此记录如何自己写一个自己的python库以及魔刀千刃的维护过程。魔刀千刃(evilblade)**只攻不防,天下无双**实战(和堆攻击帖子重合了,没关系)0x0bhitcontraining_heapcreator这是buu的pwn第二页最后一题......
  • samba--使用记录
    最近工作上参与的一个自动化项目的代码是放在一个linux上安装的git上的。在做自动化开发时,要么是远程连接到linux服务器上,然后在服务器上进行自动化开发,不过在linux操作系统上开发自动化,比较麻烦。本地电脑开发会更方便和高效一些。因此在linux装了samba.,这样可以方便本地开发自......
  • 记录一次hudi 编译过程遇到过的问题
    准备工作pom中初始依赖组件版本配置如下<java.version>1.8</java.version><hadoop.version>3.1.1.3.1.0.0-78</hadoop.version><hive.version>3.1.0.3.1.0.0-78</hive.version><kafka.version>2.0.0</kafka.version>起始命令mvncleanpack......
  • 【随手记录】harbor安装及登录
    harbor仓库安装:1、harbor包下载 https://github.com/goharbor/harbor/releases2、解压 有harbor需要的镜像包(redis、nginx、harbor-core等)和启动脚本,需要复制harbor.yml.tmpl,改为harbor.yml然后编辑此配置文件,主要调整以下三项:3、赋予脚本install.sh和prepa......
  • 记录--vue3问题:如何实现微信扫码授权登录?
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助一、需求微信扫码授权,如果允许授权,则登录成功,跳转到首页。二、问题1、微信扫码授权有几种实现方式?2、说一下这几种实现方式的原理是什么?3、vue中的微信扫码授权登录,与uniapp和原生小程序的微信授权登录,它们......
  • 记录学习day1
    今天在boss上统计了一下.net初级开发技能要求接下来就按照这个学习路线来进行了,随机找了南宁的5家公司下面是要求  前端技术:JavaScript(6)vueAjax(4)bootstrap(2)jquery(2)UniappknokoutJS(不如vue)前端库:jquery-easyuielem后端:webapi(4)ASP.NETMVC(3)多......
  • vscode使用记录
    1、ctrl+p打开全文搜索,快速查找文件(有个查找小技巧,比如需要查找一个叫DemoOpenGameInfo的文件,可以输入demoInfo,这样子可以直接排除剩下类似同名文件)2、Shift+Alt+方向键↓拷贝当前一行代码到下一行(远离ctrl+c和ctrl+v)3、Alt+方向键↓移动当前一行代码到......