习题:codevs 1519 过路费

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了习题:codevs 1519 过路费相关的知识,希望对你有一定的参考价值。

今天拿了这道题目练练手,感觉自己代码能力又增强了不少;

我的思路跟别人可能不一样。

首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这个kruskal选边建图的过程。

 1 struct kruskalsolve{
 2     int l,r,w;
 3 }kr[maxm];
此处省略的内容接下来会有给出全部代码
4 int find(int x){ 5 if(f[x] != x)f[x] = find(f[x]); 6 return f[x]; 7 } 8 void kruskal_check(int m){ 9 int cnte = 0; 10 sort(kr+1,kr+m+1,cmp); 11 for(int i = 1;i <= n;++i){ 12 f[i] = i; 13 } 14 for(int i = 1;i <= m;++i){ 15 if(cnte == n-1)break; 16 int s = find(kr[i].l); 17 int t = find(kr[i].r); 18 if(s != t){ 19 f[s] = t; 20 e[++cnte][0] = kr[i].l; 21 e[cnte][1] = kr[i].r; 22 e[cnte][2] = kr[i].w; 23 addedge(kr[i].l,kr[i].r); 24 addedge(kr[i].r,kr[i].l); 25 } 26 } 27 }

做到这里,有人可能觉得接下来一个LCA接着就可以AC了,不过蒟蒻认为这样做效率有点低,然后代码也不怎么好写,于是换成了树链剖分+线段树模板维护查询区间最大值的思路。(什么思路!!明明是套板子……这要解释的话就比较尴尬了)

这样的话效率就是O(nlogn)的总效率,感觉不错,但是就是代码量稍微有点大,请读者见谅。

建议大家还是先去学一下树链剖分的思路和板子,然后在看我的题解,毕竟光copy别人的,自己时间长了肯定忘,最好的还是自己懂了思路然后再自己手码出来。

废话不说了,上代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 using namespace std;
  7 const int maxn = 10005,maxm = 100005;
  8 int n,m,q,s,t;
  9 int id[maxn],top[maxn],son[maxn],fa[maxn],h[maxn],cnt,siz[maxn],dep[maxn],val[maxn],num,f[maxn];
 10 struct kruskalsolve{
 11     int l,r,w;
 12 }kr[maxm];
 13 struct edge{
 14     int fr,to,next;
 15 }edges[maxn<<1];
 16 struct segtree{
 17     int l,r,val;
 18 }tr[maxm<<1];
 19 int e[maxn][3];
 20 bool cmp(kruskalsolve a,kruskalsolve b){
 21     return a.w < b.w;
 22 }
 23 void init(){
 24     cnt = 0;
 25     memset(h,-1,sizeof(h));
 26     memset(dep,0,sizeof(dep));
 27     memset(siz,0,sizeof(siz));
 28     memset(fa,0,sizeof(fa));
 29     memset(id,0,sizeof(id));
 30     memset(edges,0,sizeof(edge));
 31     memset(val,0,sizeof(val));
 32     memset(e,0,sizeof(e));
 33     memset(top,0,sizeof(top));
 34     memset(tr,0,sizeof(tr));
 35     num = 0;
 36 }
 37 void addedge(int u,int v){
 38     edges[cnt].fr = u;edges[cnt].to = v;edges[cnt].next = h[u];
 39     h[u] = cnt++;
 40 }
 41 int find(int x){
 42     if(f[x] != x)f[x] = find(f[x]);
 43     return f[x];
 44 }
 45 void kruskal_check(int m){
 46     int cnte = 0;
 47     sort(kr+1,kr+m+1,cmp);
 48     for(int i = 1;i <= n;++i){
 49         f[i] = i;
 50     }
 51     for(int i = 1;i <= m;++i){
 52         if(cnte == n-1)break;
 53         int s = find(kr[i].l);
 54         int t = find(kr[i].r);
 55         if(s != t){
 56             f[s] = t;
 57             e[++cnte][0] = kr[i].l;
 58             e[cnte][1] = kr[i].r;
 59             e[cnte][2] = kr[i].w;
 60             addedge(kr[i].l,kr[i].r);
 61             addedge(kr[i].r,kr[i].l);
 62         }
 63     }
 64 }
 65 void dfs1(int now ,int father ,int d){
 66     dep[now] = d;
 67     fa[now] = father;
 68     son[now] = 0;
 69     siz[now] = 1;
 70     for(int i = h[now];i != -1;i = edges[i].next){
 71         edge e1 = edges[i];
 72         if(e1.to == father)continue;
 73         dfs1(e1.to,now,d+1);
 74         siz[now] += siz[e1.to];
 75         if(siz[son[now]] < siz[e1.to])son[now] = e1.to;
 76     }
 77 }
 78 void getpos(int now,int tp){
 79     id[now] = ++num;
 80     top[now] = tp;
 81     if(son[now])getpos(son[now],tp);
 82     for(int i = h[now];i != -1;i = edges[i].next){
 83         edge e1 = edges[i];
 84         if(e1.to == son[now] || e1.to == fa[now])continue;
 85         getpos(e1.to,e1.to);
 86     }
 87 }
 88 void push_up(int v){
 89     tr[v].val = max(tr[v<<1].val,tr[v<<1|1].val);
 90 }
 91 void build(int l,int r,int now){
 92     tr[now].l = l;
 93     tr[now].r = r;
 94     if(l == r){
 95         tr[now].val = val[l];
 96         return;
 97     }
 98     int mid = (l + r) >> 1;
 99     build(l,mid,now<<1);
100     build(mid+1,r,now<<1|1);
101     push_up(now);
102 }
103 int query(int x,int l,int r){
104     if(l <= tr[x].l && r >= tr[x].r){
105         return tr[x].val;
106     }
107     int ans = 0;
108     int mid = (tr[x].l + tr[x].r) >> 1;
109     if(l <= mid)ans = max(ans,query(x<<1,l,r));
110     if(r > mid)ans = max(ans,query(x<<1|1,l,r));
111     return ans;
112 }
113 int youth(int u,int v){
114     int ans = 0;
115     while(top[u] != top[v]){
116         if(dep[top[u]] < dep[top[v]])swap(u,v);
117         ans = max(ans,query(1,id[top[u]],id[u]));
118         u = fa[top[u]];
119     }
120     if(u == v)return ans;
121     if(dep[u] > dep[v])swap(u,v);
122     ans = max(ans,query(1,id[son[u]],id[v]));
123     return ans;
124 }
125 int main(){
126     init();
127     scanf("%d%d",&n,&m);
128     for(int i = 1;i <= m;++i){
129         scanf("%d%d%d",&kr[i].l,&kr[i].r,&kr[i].w);
130     }
131     kruskal_check(m);
132     dfs1(1,-1,1);
133     getpos(1,1);
134     for(int i = 1;i < n;++i){
135         if(dep[e[i][0]] < dep[e[i][1]])swap(e[i][0],e[i][1]);
136         val[id[e[i][0]]] = e[i][2];
137     }
138     build(1,n,1);
139     scanf("%d",&q);
140     for(int i = 1;i <= q;++i){
141         scanf("%d%d",&s,&t);
142         printf("%d\n",youth(s,t));
143     }
144     return 0;
145 }

这次写的解题报告就到这里吧,以后会尽量去写。

以上是关于习题:codevs 1519 过路费的主要内容,如果未能解决你的问题,请参考以下文章

codevs 1519 过路费

CodeVs1519 过路费

codevs http://www.codevs.cn/problem/?problemset_id=1 循环递归stl复习题

习题: codevs 2492 上帝造题的七分钟2 解题报告

习题动态规划!

矩阵乘法 codevs 1287 矩阵乘法