生成树

  生成树

  即使是基础的算法也能出很难的题啊。

  先来一个板子题:

  [模板]最小生成树:https://www.luogu.org/problemnew/show/P3366

  
 1 # include <cstdio>
 2 # include <iostream>
 3 # include <cstring>
 4 
 5 using namespace std;
 6 
 7 int G[5002][5002]={0},M[5002]={0};
 8 bool f[5002]={false};
 9 
10 int main()
11 {
12     
13     int n,m,x,y,z;
14     memset(G,0x7f,sizeof(G));
15     scanf("%d%d",&n,&m);
16     for (int i=1;i<=m;i++)
17     {
18         scanf("%d%d%d",&x,&y,&z);
19         if (G[x][y]>=z)
20           G[x][y]=G[y][x]=z;
21         }
22     memset(M,0x7f,sizeof(M));    
23     M[1]=0;
24     memset(f,1,sizeof(f));
25     for (int i=1;i<=n;i++)
26     {
27         int k=0;
28         for (int j=1;j<=n;j++)
29           if ((f[j]!=0)&&(M[j]<M[k])) k=j;
30         f[k]=false;
31         for (int j=1;j<=n;j++)
32           if (f[j]&&M[j]>G[k][j])
33             M[j]=G[k][j];
34     }
35     int A=0,S=0;
36     for (int i=1;i<=n;i++)
37       A+=f[i];
38     if (A!=0) {printf("orz");
39     return 0;}
40     for (int i=1;i<=n;i++)
41       S+=M[i];
42     cout<<S;
43     return 0;
44  } 
Prim
  
 1 // luogu-judger-enable-o2
 2 # include <cstdio>
 3 # include <iostream>
 4 # include <algorithm>
 5 # define R register int
 6 
 7 using namespace std;
 8 
 9 int fx,fy,n,m,ans,S;
10 int F[5009];
11 struct edge
12 {
13     int x,y,co;
14 }g[200009];
15 
16 bool cmp(edge a,edge b)
17 {
18     return a.co<b.co;
19 }
20 
21 int father(int x)
22 {
23     if(x!=F[x]) return F[x]=father(F[x]);
24     return x;
25 }
26 
27 int main()
28 {
29     scanf("%d%d",&n,&m);
30     S=n;
31     for (R i=1;i<=m;++i)
32         scanf("%d%d%d",&g[i].x,&g[i].y,&g[i].co);
33     sort(g+1,g+1+m,cmp);
34     for (R i=1;i<=n;++i)
35         F[i]=i;
36     for (R i=1;i<=m;++i)
37     {
38         fx=father(g[i].x);
39         fy=father(g[i].y);
40         if(fx!=fy)
41             F[fx]=fy,S--,ans+=g[i].co;
42     }
43     if(S!=1)
44         printf("orz");
45     else
46         printf("%d",ans);
47     return 0;
48 }
Kruskal

  $Prim$的时间复杂度:$O(V^{2})$

  $Kruskal$时间复杂度:$O(ElogE)$

  虽然$Kruskal$用的比较多,但是在处理近乎完全图的时候还是$Prim$比较快($E=V^{2}$)

  听说还有一种针对没有重复权值的图的算法:$Boruvka$,对于随机图来说$O(V+E)$,听起来还是很不错的,不过我觉得现在还没必要学这个。

 

  爱的供养:https://www.luogu.org/problemnew/show/P2266

 

  昨天做了NOI同步赛,赛后学了一种感觉很有用的Kruskal重构树,现在通过一道题来学习一下。

  归程:https://www.luogu.org/problemnew/show/P4768

  题意概述:给定一张无向图,每条边有长度和海拔,每次给定一个起点和水平面,要求开车走海拔高于水平面的边,再找一个地方下车走,最终到达1号,求走路这一部分的最小长度,强制在线。

  先从一号点跑$Dijkstra$求出每一个点到一号点的最短路,这一步是不可能省略的。现在考虑暴力,每次读入起点后跑BFS,可以得到50分。考虑离线,按照每次的水平面进行排序,把高于水平面的点进行合并(并查集),在同一个并查集中的点说明可以开车互相到达,这个并查集的权值就是这一些点里面离一号最近的点的权值。说的好,但是强制在线啊。可持久化并查集听说有卡过的,然而我不会。

  看看合并的顺序像不像一棵树呀。首先按照海拔排序,用kruskal的思路进行合并,每次将$f[u]$,$f[v]$连到一个新建的虚点上:点权为这条边的海拔,显然全部合并完后就会形成一棵树,这棵树就叫kruskal重构树。每次我们在这棵树上往上爬,当爬到最大的小于这次海平面的点时就说明如果海平面是这么大,这个点就只能合并到这里为止了。因为重构出的树的点权是单调的,可以树上倍增。如果学过这个算法的话这道题其实就是个模板,对于NOI选手应该是签到题?(听说这题卡SPFA)

  
  1 // luogu-judger-enable-o2
  2 # include <cstdio>
  3 # include <cstring>
  4 # include <iostream>
  5 # include <queue>
  6 # include <set>
  7 # include <algorithm>
  8 # define R register int
  9 
 10 inline int min (int a,int b) { if(a<b) return a; return b; }
 11 const int maxn=5e5+10;
 12 const int maxm=2e6+10;
 13 int cnt,T,n,m,h,da,k,s,fx,fy,u,v,l,a,p;
 14 int kh,firs[maxn<<1],F[maxn<<1][22],f[maxn<<1],val[maxn<<1];
 15 bool vis[maxn<<1];
 16 long long d[maxn<<1],ans=0,mind[maxn<<1];
 17 typedef std::pair <long long,int> pii;
 18 std::priority_queue <pii,std::vector<pii>,std::greater<pii> > q;
 19 int firs_k[maxm<<1];
 20 struct edge
 21 {
 22     int too,nex,l,a; //l长度,a海拔 
 23 }g[maxm<<1];
 24 struct lin
 25 {
 26     int x,y,a;
 27 }G[maxm];
 28 struct kru_tree
 29 {
 30     int nex,too;
 31 }kru[maxm<<1];
 32 
 33 inline void add (int x,int y,int l,int a)
 34 {
 35     g[++h].too=y;
 36     g[h].nex=firs[x];
 37     g[h].l=l;
 38     g[h].a=a;
 39     firs[x]=h;
 40 }
 41 
 42 inline void dij (int s)
 43 {
 44     memset(d,127,sizeof(d));
 45     memset(vis,0,sizeof(vis));
 46     d[s]=0;
 47     while (q.size()) q.pop();
 48     q.push(std::make_pair(d[s],s));
 49     int j,beg;
 50     while (q.size())
 51     {
 52         beg=q.top().second;
 53         q.pop();
 54         if(vis[beg]) continue;
 55         vis[beg]=true;
 56         for (R i=firs[beg];i;i=g[i].nex)
 57         {
 58             j=g[i].too;
 59             if(d[beg]+g[i].l>=d[j]) continue;
 60             d[j]=d[beg]+g[i].l;
 61             q.push(std::make_pair(d[j],j));
 62         }
 63     }
 64 }
 65 
 66 void add_edge(int x,int y)
 67 {
 68     kru[++kh].too=y;
 69     kru[kh].nex=firs_k[x];
 70     firs_k[x]=kh;
 71 }
 72 
 73 bool cmp (lin a,lin b)
 74 {
 75     return a.a>b.a;
 76 }
 77 
 78 int father (int x) { return f[x]?f[x]=father(f[x]):x; }
 79 
 80 void dfs (int x)
 81 {
 82     for (R i=firs_k[x];i;i=kru[i].nex)
 83         dfs(kru[i].too),mind[x]=min(mind[x],mind[ kru[i].too]),F[ kru[i].too ][0]=x;
 84     if(x<=n) mind[x]=d[x];
 85 }
 86 
 87 int main()
 88 {
 89     scanf("%d",&T);
 90     while (T--)
 91     {
 92         scanf("%d%d",&n,&m);
 93         ans=0,cnt=n,kh=0;
 94         memset(firs,0,sizeof(firs));
 95         memset(F,0,sizeof(F));
 96         memset(mind,127,sizeof(mind));
 97         memset(firs_k,0,sizeof(firs_k));
 98         memset(f,0,sizeof(f));
 99         memset(val,0,sizeof(val));
100         h=0;
101         for (R i=1;i<=m;++i)
102         {
103             scanf("%d%d%d%d",&u,&v,&l,&a);
104             add(u,v,l,a);
105             add(v,u,l,a);
106             G[i].x=u;
107             G[i].y=v;
108             G[i].a=a;
109         }
110         dij(1);
111         std::sort(G+1,G+1+m,cmp);
112         for (R i=1;i<=m;++i)
113         {
114             fx=father(G[i].x);
115             fy=father(G[i].y);
116             if(fx==fy) continue;
117             f[fx]=f[fy]=++cnt;
118             add_edge(cnt,fx);
119             add_edge(cnt,fy);
120             val[cnt]=G[i].a;
121         }
122         dfs(cnt);
123         scanf("%d%d%d",&da,&k,&s);
124         for (int j=1;j<=21;++j)
125             for (int i=1;i<=cnt;++i)
126                 F[i][j]=F[ F[i][j-1] ][j-1];
127         for (R i=1;i<=da;++i)
128         {
129             scanf("%d%d",&v,&p);
130             v=(v+(long long)k*ans-1)%n+1;
131             p=(p+(long long)k*ans)%(s+1);
132             for (int j=21;j>=0;--j)
133                 if(val[ F[v][j] ]>p) v=F[v][j];
134             ans=mind[v];
135             printf("%lld\n",ans);
136         }
137     }
138     return 0;
139 }
归程

 

posted @ 2018-06-28 17:22  shzr  阅读(175)  评论(0编辑  收藏  举报