题目链接:http://uoj.ac/problem/30
题目大意:给定一张无向连通图,每个点有点权,多次询问两个点之间的简单路径上最小点权值的最小值
首先求的是最小点权值的最小值 那么我们肯定要走点权越小的点越好 但是由于求的是简单路径 那么我们就不能经过同一个点两次
那么我们Tarjan求点双联通分量 每个点双维护一个最小值 那么答案显然就是两点所在点双路径上的最小值 树链剖分即可 (正确性我不会证
但是一个割点可以属于多个点双 因此割点在计算距离的时候要取最近的那个点双 建图时对于每一个割点建一个权值为+∞的虚点连向所有所在的点双即可
那么问题来了:由于一个割点可以属于多个点双 那么修改一个点的权值就要更新多个点双 如果这个图是一朵菊花 那么岂不直接被卡到O(n^2)?
因此 对于每个割点 我们只用这个割点所在虚点的父亲点双来维护这个点
如果所求的两个点的LCA是虚点 那么就统计这个虚点所代表的点的点权 如果LCA是点双 那么就把这个点双的父亲节点加入统计
然后基本就可以了 Tarjan求点双容易写挂 注意一下
看到神犇们的代码7KB+着实吓了一跳&…… 写完发现只有4KB…… 结果我第一,又快又好写……
#include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 #define INF 0x3f3f3f3f using namespace std; struct BCC{ multiset<int>s; int value; inline void Insert(int x) { s.insert(x); value=*s.begin(); } inline void Modify(int x,int y) { s.erase( s.find(x) ); s.insert(y); value=*s.begin(); } }BCCs[M<<1]; namespace ZKW_Segtree{ int tree[263000<<1]={INF}; int q; void Build_Tree(int a[],int n) { int i; for(q=1;q<=n+1;q<<=1); for(i=1;i<=n;i++) tree[q+i]=a[i]; for(i=q-1;i;i--) tree[i]=min(tree[i<<1],tree[i<<1|1]); } void Modify(int x,int y) { tree[x+=q]=y; while(x>>=1) tree[x]=min(tree[x<<1],tree[x<<1|1]); } int Get_Ans(int x,int y) { int re=INF; for(x+=q-1,y+=q+1;x^y^1;x>>=1,y>>=1) { if(~x&1) re=min(re,tree[x^1]); if( y&1) re=min(re,tree[y^1]); } return re; } } int n,m,q,cnt; int a[M],belong[M]; bool v[M]; namespace New_Map{ struct abcd{ int to,next; }table[M<<2]; int head[M<<1],tot; int fa[M<<1],son[M<<1],dpt[M<<1],size[M<<1],top[M<<1],pos[M<<1],posf[M<<1],T; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS1(int x) { int i; size[x]=1; dpt[x]=dpt[fa[x]]+1; for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) { fa[table[i].to]=x; DFS1(table[i].to); size[x]+=size[table[i].to]; if(size[table[i].to]>size[son[x]]) son[x]=table[i].to; } } void DFS2(int x) { int i; if(son[fa[x]]==x) top[x]=top[fa[x]]; else top[x]=x; posf[pos[x]=++T]=BCCs[x].value; if(son[x]) DFS2(son[x]); for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]&&table[i].to!=son[x]) DFS2(table[i].to); } int LCA(int x,int y) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); x=fa[fx];fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y); return y; } void Make_Graph() { int i; memset(posf,0x3f,sizeof posf); DFS1(n+1);DFS2(n+1); ZKW_Segtree::Build_Tree(posf,T); } int Query(int x,int y) { int re,fx=top[x],fy=top[y],temp=LCA(x,y); if(temp<=cnt) temp=fa[temp];re=a[temp-n]; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); re=min(re,ZKW_Segtree::Get_Ans(pos[fx],pos[x])); x=fa[fx];fx=top[x]; } if(dpt[x]<dpt[y]) swap(x,y); re=min(re,ZKW_Segtree::Get_Ans(pos[y],pos[x])); return re; } } namespace Ori_Map{ struct abcd{ int to,next; }table[M<<1]; int head[M],tot; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void Tarjan(int x) { static int stack[M],top; static int dpt[M],low[M],T; int i; dpt[x]=low[x]=++T; stack[++top]=x; for(i=head[x];i;i=table[i].next) { if(dpt[table[i].to]) low[x]=min(low[x],dpt[table[i].to]); else { Tarjan(table[i].to); low[x]=min(low[x],low[table[i].to]); if(dpt[x]==low[table[i].to]) { int t;++cnt; v[x]=1; do{ t=stack[top--]; belong[t]=cnt; if(v[t]) { New_Map::Add(t+n,cnt); New_Map::Add(cnt,t+n); } }while(t!=table[i].to); New_Map::Add(x+n,cnt); New_Map::Add(cnt,x+n); } } } } inline void Make_Graph() { int i; Tarjan(1); for(i=1;i<=n;i++) { if(i!=1) BCCs[ belong[i] ].Insert(a[i]); if(v[i]) BCCs[i+n].Insert(INF); } New_Map::Make_Graph(); } } int main() { //freopen("30.in","r",stdin); //freopen("30.out","w",stdout); int i,x,y; char p[10]; cin>>n>>m>>q; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) scanf("%d%d",&x,&y),Ori_Map::Add(x,y),Ori_Map::Add(y,x); Ori_Map::Make_Graph(); for(i=1;i<=q;i++) { scanf("%s%d%d",p,&x,&y); if(p[0]=='C') { if(x!=1) { BCCs[belong[x]].Modify(a[x],y); ZKW_Segtree::Modify(New_Map::pos[belong[x]],BCCs[belong[x]].value); } a[x]=y; } else { if(x==y) { printf("%d\n",a[x]); continue; } x=v[x]?x+n:belong[x]; y=v[y]?y+n:belong[y]; printf("%d\n", New_Map::Query(x,y) ); } } return 0; }