codancer的图论训练(updating...)

2019.9.12

----580C.Kefa and Park
tags: 简单DFS
code

----1081D.Maximum Distance
tags:带点思维的MST,学会了只联通某些点的并查集
code

2019.9.13

----1095F.Make It Connected
n 2 + m n^2+m n2+m条边的MST,只需要考虑 n + m n+m n+m条即可。
code

----1037D. Valid BFS?
判断给出的序列是否是合法的BFS序。
code

2019.9.25 (Hihocoder)

----1190.连通性四
点双连通裸题,对每个边分配点双连通的id即可。

2019.9.26

51nod.1076.2条不相交的路径
利用Tarjan求边双连通分量,对于在同一个分量中的点,则存在至少两条不相交的路径。
luogu.p1113杂物
简单的拓扑排序,更新任务 i i i结束后的最晚时间即可。

2019.9.30

1228D. Complete Tripartite
判定给定的图是否是可以分为三个点集,使得任意两个点集之间满足完全二分关系。
sol:先把第一个点放到第一个点集中,然后和1不相连的也放到第一个点集中,以此类推找到三个集和。
1.如果有的点不在这三个点集中,则不能。
2.如果任意两个点集之间不能满足任意两点有边,则不能。
3. s 1 s 2 + s 1 s 3 + s 2 s 3 ≠ m s_1s_2+s_1s_3+s_2s_3 \neq m s1s2+s1s3+s2s3=m则不能,其中 s i s_i si代表第 i i i个点集的大小。
code

2019.11.28

786B.Legacy
区间最短路经典题目,线段树优化建图。
code

#include<bits/stdc++.h>
 
using namespace std;
const int N = 5e5+100;
typedef long long ll;
const ll INF = (1e18);
//最短路部分
vector<pair<int,ll> > G[N];
ll dis[N];
bool vis[N];
void addedge(int u,int v,int w){
  G[u].push_back({v,w});
}
struct node{
  int id;
  ll d;
};
bool operator<(node a,node b){
  return a.d>b.d;
}
void dij(int s,int n){//起点为s,总点数为n的最短路
  priority_queue<node> q;
  for(int i=1;i<=n;i++){
    dis[i]=INF;vis[i]=0;
  }
  dis[s]=0;
  q.push({s,0});
  while(!q.empty()){
    node now=q.top();q.pop();
    int u=now.id;
    if(vis[u]) continue;
    vis[u]=1;
    for(auto V:G[u]){
      int v=V.first;
      ll w=V.second;
      if(dis[v]>dis[u]+w){
        dis[v]=dis[u]+w;
        q.push({v,dis[v]});
      }
    }
  }
}
 
int cnt;//总点数
struct Segment{
  int id[N*4];
  void buildtree(int rt,int l,int r,bool up){//建树,判断是上树还是下数
    id[rt]=++cnt;
    if(l==r){
      int u=id[rt];
      int v=l;
      if(up) swap(u,v);
      addedge(u,v,0);//父子建边
      return ;
    }
    int mid=(l+r)>>1;
    buildtree(rt<<1,l,mid,up);
    buildtree(rt<<1|1,mid+1,r,up);
    int u=id[rt];
    int v=id[rt<<1];
    if(up) swap(u,v);
    addedge(u,v,0);
    u=id[rt];
    v=id[rt<<1|1];
    if(up) swap(u,v);
    addedge(u,v,0);
  }
  void add_edge(int rt,int l,int r,int nl,int nr,int T,int w,bool up){//[nl,nr]<->T based on up
    if(nl<=l&&r<=nr){
      int u=id[rt];
      int v=T;
      if(up) swap(u,v);
      addedge(u,v,w);
      return ;
    }
    int mid=(l+r)>>1;
    if(nl<=mid) add_edge(rt<<1,l,mid,nl,nr,T,w,up);
    if(nr>mid) add_edge(rt<<1|1,mid+1,r,nl,nr,T,w,up);
  }
}UP,DOWN;
int main(){
  int n,q,s;
  cin>>n>>q>>s;
  cnt=n;
  UP.buildtree(1,1,n,1);
  DOWN.buildtree(1,1,n,0);
  int op,u,v,w,l,r;
  for(int i=1;i<=q;i++){
    cin>>op;
    if(op==1){
      cin>>u>>v>>w;
      addedge(u,v,w);
    }
    if(op==2){//v->[l,r] down为true
      cin>>v>>l>>r>>w;
      DOWN.add_edge(1,1,n,l,r,v,w,1);
    }
    if(op==3){//[l,r]->x
      cin>>v>>l>>r>>w;
      UP.add_edge(1,1,n,l,r,v,w,0);
    }
  }
  dij(s,cnt);
  for(int i=1;i<=n;i++){
    if(dis[i]==INF) dis[i]=-1;
    if(i==1) cout<<dis[i];
    else cout<<' '<<dis[i];
  }
  cout<<endl;
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值