习题: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 }
这次写的解题报告就到这里吧,以后会尽量去写。