101889I Imperial roads (樹鏈剖分維護邊權最大值)
阿新 • • 發佈:2018-12-15
題意:給你一個圖,然後Q個詢問,每個詢問,問強制要求使用某條邊的情況下的最小生成樹。
解題思路:先求最小生成樹,然後對於強制要求的邊,直接查詢樹上路徑最大值,然後減去這個最大值,再加上要求的邊的權值就是答案。
直接上樹鏈剖分即可。
#include<bits/stdc++.h> using namespace std; const int MAXN=400005; typedef long long ll; map<pair<int,int>,int > mp; struct edge{ int u,v,w,next; }ee[MAXN]; bool cmp(edge a,edge b){ return a.w<b.w; } edge e[MAXN]; int edge_num=0; int head[MAXN]; void insert_edge(int u,int v,int w){ e[edge_num].u=u; e[edge_num].v=v; e[edge_num].w=w; e[edge_num].next=head[u]; head[u]=edge_num++; } int pre[MAXN]; int find(int x){ return x==pre[x]?x:pre[x]=find(pre[x]); } //樹鏈剖分部分 int top[MAXN];//重鏈頂點 int fa[MAXN];//父親節點 int deep[MAXN];//深度 int size[MAXN];//子樹大小 int pos[MAXN];//dfs序 int son[MAXN];//重兒子是哪個 int SEG;//dfs序當前點 int N,M; void init(){ edge_num=0; memset(head,-1,sizeof(head)); SEG=1; memset(son,-1,sizeof(son)); } //求出fa,deep,num,son void dfs1(int u,int pre,int d){ deep[u]=d; fa[u]=pre; size[u]=1; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v!=pre){ dfs1(v,u,d+1); size[u]+=size[v]; if(son[u]==-1||size[v]>size[son[u]]) son[u]=v; } } } //求出top和pos,求的過程中,先求重鏈上的dfs序 void dfs2(int u,int sp){ top[u]=sp; if(son[u]!=-1){ pos[u]=SEG++; dfs2(son[u],sp); } else{ pos[u]=SEG++; return; } for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v!=son[u]&&v!=fa[u]){ dfs2(v,v); } } } //線段樹部分 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int MAX[MAXN<<2]; int val[MAXN<<2]; void pushup(int rt){ MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); } void build(int l,int r,int rt){ if(l==r){ MAX[rt]=val[l]; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(l>=L&&r<=R){ return MAX[rt]; } int m=(l+r)>>1; int res=0; if(m>=L) res=max(res,query(L,R,lson)); if(R>m) res=max(res,query(L,R,rson)); return res; } //線段樹+樹鏈剖分部分 int query(int u,int v){ int f1=top[u],f2=top[v]; int temp=0; while(f1!=f2){ if(deep[f1]<deep[f2]){ swap(f1,f2); swap(u,v); } temp=max(temp,query(pos[f1],pos[u],1,N,1)); u=fa[f1]; f1=top[u]; } if(u==v) return temp; if(deep[u]>deep[v]) swap(u,v); //cout<<son[u]<<" "<<v<<endl; return max(temp,query(pos[son[u]],pos[v],1,N,1));//因為是邊權,所以是pos[son[u]] } int main(){ init(); for(int i=0;i<MAXN;i++) pre[i]=i; int u,v; scanf("%d%d",&N,&M); for(int i=0;i<M;i++){ scanf("%d%d%d",&ee[i].u,&ee[i].v,&ee[i].w); mp[make_pair(ee[i].u,ee[i].v)]=ee[i].w; mp[make_pair(ee[i].v,ee[i].u)]=ee[i].w; } sort(ee,ee+M,cmp); int ans=0; for(int i=0;i<M;i++){ u=ee[i].u; v=ee[i].v; int fx=find(u); int fy=find(v); if(fy!=fx){ ans+=ee[i].w; pre[fx]=fy; insert_edge(u,v,ee[i].w); insert_edge(v,u,ee[i].w); } } dfs1(1,0,0); dfs2(1,1); for(int i=0;i<edge_num;i+=2){ if(deep[e[i].u]<deep[e[i].v]) val[pos[e[i].v]]=e[i].w; else val[pos[e[i].u]]=e[i].w; } build(1,N,1); int Q; scanf("%d",&Q); while(Q--){ scanf("%d%d",&u,&v); int mm=query(u,v); cout<<ans-mm+mp[make_pair(u,v)]<<endl; } return 0; }