标签:注意 码农题 pac inf 双连通分量 bool 查询 struct 很多
题意:一个无向连通图,点有点权,支持单点修改和查询,查询$(x,y)$是找出一条$x$到$y$的简单路径使得路径点权最小值最小,输出这个最小值
码农题...而且细节很多...
先找边双连通分量缩点,对于每个边双,新建一个节点和边双中的每个点连边,不属于任何边双的边就直接连,这样可以建出一棵树,然后就变成树上的问题了,因为进入一个边双就可以遍历它的所有点
对于新建的点,开一个multiset存它儿子的权值,它自己的权值设为multiset的最小值
查询就是路径$\min$,注意如果lca是新建点,那么这个lca的父亲的权值也应该被统计
修改就修改单点,如果父亲是新建点就更新它的multiset还有权值
注意在tarjan时栈中保存的应该是边而不是点
#include<stdio.h> #include<vector> #include<set> using namespace std; const int inf=2147483647; int v[100010],n,m,q,C; struct tree{ int h[200010],nex[400010],to[400010],M; multiset<int>s[200010]; void ins(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } void add(int a,int b){ ins(a,b); ins(b,a); } int fa[200010][18],dep[200010]; void dfs(int x){ dep[x]=dep[fa[x][0]]+1; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0]){ if(x>n)s[x].insert(v[to[i]]); fa[to[i]][0]=x; dfs(to[i]); } } if(x>n)v[x]=*s[x].begin(); } int lca(int x,int y){ int i; if(dep[x]<dep[y])swap(x,y); for(i=17;i>=0;i--){ if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; } if(x==y)return x; for(i=17;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } int siz[200010],son[200010],pos[200010],bl[200010]; void dfs1(int x){ int i,k=0; siz[x]=1; for(i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0]){ dfs1(to[i]); siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[k])k=to[i]; } } son[x]=k; } void dfs2(int x,int chain){ pos[x]=++M; bl[x]=chain; if(son[x])dfs2(son[x],chain); for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0]&&to[i]!=son[x])dfs2(to[i],to[i]); } } int T[800010]; void modify(int x,int v){ T[x+=M]=v; for(x>>=1;x;x>>=1)T[x]=min(T[x<<1],T[x<<1|1]); } int query(int s,int t){ int res=inf; for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){ if(~s&1)res=min(res,T[s^1]); if(t&1)res=min(res,T[t^1]); } return res; } void gao(){ int i,j; dfs(1); for(j=1;j<18;j++){ for(i=1;i<=C;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; } dfs1(1); M=0; dfs2(1,1); for(M=1;M<=C+1;M<<=1); for(i=0;i<M;i++)T[i+M]=inf; for(i=1;i<=C;i++)T[pos[i]+M]=v[i]; for(i=M-1;i>0;i--)T[i]=min(T[i<<1],T[i<<1|1]); } int querych(int x,int y){ int res=inf; while(bl[x]!=bl[y]){ if(dep[bl[x]]<dep[bl[y]])swap(x,y); res=min(res,query(pos[bl[x]],pos[x])); x=fa[bl[x]][0]; } if(pos[x]>pos[y])swap(x,y); res=min(res,query(pos[x],pos[y])); if(x>n)res=min(res,v[fa[x][0]]); return res; } void modifypt(int x,int d){ if(fa[x][0]&&fa[x][0]>n){ s[fa[x][0]].erase(s[fa[x][0]].find(v[x])); s[fa[x][0]].insert(d); modify(pos[fa[x][0]],*s[fa[x][0]].begin()); } v[x]=d; modify(pos[x],d); } }tr; struct graph{ int h[100010],nex[200010],to[200010],M; graph(){M=1;} int fix(int i){return i&1?i^1:i;} void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } int dfn[100010],low[100010],stk[100010],vis[100010],tp,K; bool ins[200010]; vector<int>V; void dfs(int x){ int i,j,t,n,m; dfn[x]=low[x]=++M; for(i=h[x];i;i=nex[i]){ if(!dfn[to[i]]){ ins[stk[++tp]=fix(i)]=1; dfs(to[i]); low[x]=min(low[x],low[to[i]]); if(low[to[i]]>=dfn[x]){ K++; V.clear(); j=tp; m=0; do{ t=stk[j--]; m++; if(vis[to[t]]!=K){ vis[to[t]]=K; V.push_back(to[t]); } if(vis[to[t^1]]!=K){ vis[to[t^1]]=K; V.push_back(to[t^1]); } }while(t!=fix(i)); n=V.size(); if(m<n) tr.add(x,to[i]); else{ C++; for(int x:V)tr.add(x,C); } do{ ins[t=stk[tp--]]=0; }while(t!=fix(i)); } }else{ low[x]=min(low[x],dfn[to[i]]); if(!ins[fix(i)]&&dfn[to[i]]<dfn[x])ins[stk[++tp]=fix(i)]=1; } } } void gao(){ int i,x,y; for(i=1;i<=n;i++)scanf("%d",v+i); for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } M=0; C=n; dfs(1); } }g; int main(){ char s[5]; int x,y; scanf("%d%d%d",&n,&m,&q); g.gao(); tr.gao(); while(q--){ scanf("%s%d%d",s,&x,&y); if(s[0]==‘C‘) tr.modifypt(x,y); else printf("%d\n",tr.querych(x,y)); } }
标签:注意 码农题 pac inf 双连通分量 bool 查询 struct 很多
原文地址:https://www.cnblogs.com/jefflyy/p/9480473.html