Gym - 101889I Imperial roads(最小生成树+树链剖分+线段树)
生活随笔
收集整理的這篇文章主要介紹了
Gym - 101889I Imperial roads(最小生成树+树链剖分+线段树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:給出一個由n個節點組成的無向圖,現在給出m次詢問,每次詢問給出一組u和v,問若使用u-v這條邊所能組成的最小生成樹的權值是多少
題目分析:題意描述的很清楚,但當然不能直接根據題意模擬,因為肯定會超時。。一次Kruskal算法的時間復雜度是O(邊數),如果進行m次的話,時間復雜度就是m*邊數,兩項都拉滿的話也得1e10了,肯定是不行的,那么我們該怎么辦呢?最小生成樹的話是用n-1條邊,來連接n個點,所以我們可以一開始就求一次最小生成樹,然后分為兩種情況討論:
綜上所述,先把最小生成樹剖一下然后直接線段樹維護最大值就行了
寫這個題花了10分鐘,調了一晚上,還是因為代碼寫的不夠多,寫模板沒有練成肌肉記憶的效果,導致三番五次的犯低級錯誤,讓自己氣急敗壞卻束手無策,多做題才是硬道理,像樹鏈剖分樹上倍增的模板應該越寫越熟才行,說白了還是做題少,得繼續努力啊
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;int n,m;struct Node {int to,w;Node(int TO,int W){to=TO;w=W;} };vector<Node>node[N];//鄰接表 struct Edge {int u,v,w;bool operator<(const Edge& a)const{return w<a.w;} }edge[N<<1];//存邊 map<pair<int,int>,bool>vis;//記錄最小生成樹中的邊 map<pair<int,int>,int>vis2;//記錄每個邊的權值 pair<int,int> mp(int a,int b) {return make_pair(a,b); }int f[N];//并查集用 int find(int x) {return x==f[x]?x:f[x]=find(f[x]); }int Kruskal() {for(int i=1;i<=n;i++)f[i]=i;sort(edge+1,edge+1+m);int cnt_edge=0;int sum=0;for(int i=1;i<=m;i++){int u=edge[i].u;int v=edge[i].v;int w=edge[i].w;int uu=find(u);int vv=find(v);if(uu!=vv){f[uu]=vv;sum+=w;vis[mp(u,v)]=vis[mp(v,u)]=true;node[u].push_back(Node(v,w));node[v].push_back(Node(u,w));cnt_edge++;if(cnt_edge==n-1)break;}}return sum; }int deep[N],son[N],fa[N],num[N],val[N];//val[節點]=權值 void dfs1(int u,int f,int dep) {deep[u]=dep;fa[u]=f;son[u]=-1;num[u]=1;for(auto i:node[u]){int v=i.to;int w=i.w;if(v==f)continue;dfs1(v,u,dep+1);val[v]=w;num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;} }int top[N],id[N],idd[N],cnt;//id[節點]=編號 idd[編號]=節點 void dfs2(int u,int f,int root) {top[u]=root;id[u]=++cnt;idd[cnt]=u;if(son[u]!=-1)dfs2(son[u],u,root);for(auto i:node[u]){int v=i.to;if(v==f||v==son[u])continue;dfs2(v,u,v);} }struct tree {int l,r,mmax; }tree[N<<2];void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;if(l==r){tree[k].mmax=val[idd[l]];return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax); }int query(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmax;return max(query(k<<1,l,r),query(k<<1|1,l,r)); }int solve(int a,int b) {int mmax=0;while(top[a]!=top[b]){if(deep[top[a]]<deep[top[b]])swap(a,b);mmax=max(mmax,query(1,id[top[a]],id[a]));a=fa[top[a]];}if(a==b)return mmax;if(deep[a]>deep[b])swap(a,b);mmax=max(mmax,query(1,id[a]+1,id[b]));return mmax; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);vis2[mp(edge[i].u,edge[i].v)]=edge[i].w;vis2[mp(edge[i].v,edge[i].u)]=edge[i].w;}int sum=Kruskal();dfs1(1,0,0);dfs2(1,0,1);build(1,1,n);int w;scanf("%d",&w);while(w--){int u,v;scanf("%d%d",&u,&v);if(vis[mp(u,v)])printf("%d\n",sum);elseprintf("%d\n",sum+vis2[mp(u,v)]-solve(u,v));}return 0; }?
總結
以上是生活随笔為你收集整理的Gym - 101889I Imperial roads(最小生成树+树链剖分+线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 5452 Minimum C
- 下一篇: POJ - 3417 Network(树