Codeforces 487E
题意:
给出一个无向联通图,求一个点不经过重复点可以到达点的最小权值,需要兹瓷修改权值。
先求点双连通分量,然后缩点,形成一棵树,每个新点的权值是其中所有点的最小权值。
然额,割点属于多个点双连通分量,每次直接修改会TLE(一棵菊花树就可以做到),
所以对每个点双新建一个结点,对属于它的点连边,这样每个原来的点的父亲一定是它所属的点双。
之后对每个点双建一个multiset维护最小值,查询时用树链剖分加线段树。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <set> 5 using namespace std; 6 #define maxn 100001 7 template<typename __> 8 inline void read(__ &s) 9 { 10 char ch; 11 for(ch=getchar(),s=0;ch<'0'||ch>'9';ch=getchar()); 12 for(;ch>='0'&&ch<='9';ch=getchar()) 13 s=s*10+ch-'0'; 14 } 15 struct edge 16 { 17 int u,v,nex; 18 }e[maxn<<1]; 19 int pr[maxn],cnt; 20 void add(int u,int v) 21 { 22 e[++cnt]=(edge){u,v,pr[u]}; 23 pr[u]=cnt; 24 e[++cnt]=(edge){v,u,pr[v]}; 25 pr[v]=cnt; 26 } 27 int n,m,bcc_cnt,bcc_dfn,top,q; 28 int dfn[maxn],low[maxn],cut[maxn<<1]; 29 int s[maxn],belong[maxn<<1],st[maxn]; 30 multiset<int>mst[maxn]; 31 class seg 32 { 33 public: 34 struct edge 35 { 36 int u,v,nex; 37 }e[maxn<<2]; 38 int cnt,dfn,N; 39 int siz[maxn<<1],depth[maxn<<1],top[maxn<<1],pr[maxn<<1]; 40 int son[maxn<<1],fa[maxn<<1],L[maxn<<1],quit[maxn<<1]; 41 bool vis[maxn<<1]; 42 multiset<int>::iterator it; 43 void add(int u,int v) 44 { 45 e[++cnt]=(edge){u,v,pr[u]}; 46 pr[u]=cnt; 47 e[++cnt]=(edge){v,u,pr[v]}; 48 pr[v]=cnt; 49 } 50 void dfs_make(int u) 51 { 52 int v; 53 siz[u]=vis[u]=1; 54 for(int i=pr[u];i;i=e[i].nex) 55 { 56 v=e[i].v; 57 if(!vis[v]) 58 { 59 depth[v]=depth[u]+1; 60 fa[v]=u; 61 dfs_make(v); 62 siz[u]+=siz[v]; 63 if(siz[v]>siz[son[u]]) 64 son[u]=v; 65 } 66 } 67 } 68 void dfs_lines(int u,int f) 69 { 70 int v; 71 vis[u]=1; 72 L[u]=++dfn; 73 quit[dfn]=u; 74 top[u]=f; 75 if(son[u]) 76 dfs_lines(son[u],f); 77 for(int i=pr[u];i;i=e[i].nex) 78 { 79 v=e[i].v; 80 if(!vis[v]) 81 dfs_lines(v,v); 82 } 83 } 84 struct node 85 { 86 int minn; 87 }tree[maxn<<3]; 88 #define lson id<<1,l,mid 89 #define rson id<<1|1,mid+1,r 90 #define INF 0x7fffffff 91 inline void pushup(int id) 92 { 93 tree[id].minn=min(tree[id<<1].minn,tree[id<<1|1].minn); 94 } 95 void build(int id,int l,int r) 96 { 97 if(l==r) 98 { 99 tree[id].minn=s[quit[l]]; 100 return ; 101 } 102 int mid=(l+r)>>1; 103 build(lson); 104 build(rson); 105 pushup(id); 106 } 107 int query(int id,int l,int r,int L,int R) 108 { 109 if(L<=l&&r<=R) 110 return tree[id].minn; 111 int mid=(l+r)>>1; 112 if(R<=mid) 113 return query(lson,L,R); 114 else 115 if(L>mid) 116 return query(rson,L,R); 117 else 118 return min(query(lson,L,mid),query(rson,mid+1,R)); 119 } 120 void update(int id,int l,int r,int pos,int val) 121 { 122 if(l==r) 123 { 124 tree[id].minn=val; 125 return ; 126 } 127 int mid=(l+r)>>1; 128 if(pos<=mid) 129 update(lson,pos,val); 130 else 131 update(rson,pos,val); 132 pushup(id); 133 } 134 int query(int u,int v) 135 { 136 int ans=INF; 137 while(top[u]!=top[v]) 138 { 139 if(depth[top[u]]<depth[top[v]]) 140 swap(u,v); 141 ans=min(ans,query(1,1,N,L[top[u]],L[u])); 142 u=fa[top[u]]; 143 } 144 if(depth[u]>depth[v]) 145 swap(u,v); 146 ans=min(ans,query(1,1,N,L[u],L[v])); 147 if(u>n) 148 ans=min(ans,s[fa[u]]); 149 return ans; 150 } 151 void init() 152 { 153 N=bcc_cnt; 154 dfs_make(1); 155 memset(vis,0,sizeof(vis)); 156 dfs_lines(1,1); 157 for(int i=1;i<=n;i++) 158 if(fa[i]>n) 159 mst[fa[i]-n].insert(s[i]); 160 for(int i=n+1;i<=N;i++) 161 { 162 it=mst[i-n].begin(); 163 s[i]=*it; 164 } 165 build(1,1,N); 166 } 167 void change(int pos,int val) 168 { 169 int p=fa[pos]-n; 170 if(p>0) 171 { 172 it=mst[p].find(s[pos]); 173 mst[p].erase(it); 174 mst[p].insert(val); 175 it=mst[p].begin(); 176 s[fa[pos]]=(*it); 177 update(1,1,N,L[fa[pos]],s[fa[pos]]); 178 } 179 update(1,1,N,L[pos],val); 180 s[pos]=val; 181 } 182 }T; 183 int find_fa(int x) 184 { 185 if(belong[x]==x) 186 return x; 187 return belong[x]=find_fa(belong[x]); 188 } 189 void UN(int x,int y) 190 { 191 int xx=find_fa(x),yy=find_fa(y); 192 if(xx!=yy) 193 belong[xx]=yy; 194 } 195 void tarjan(int u,int f) 196 { 197 int num=0,k,v; 198 st[++top]=u; 199 dfn[u]=low[u]=++bcc_dfn; 200 for(int i=pr[u];i;i=e[i].nex) 201 { 202 v=e[i].v; 203 if(!dfn[v]) 204 { 205 tarjan(v,u); 206 low[u]=min(low[u],low[v]); 207 if(low[v]>=dfn[u]) 208 { 209 cut[u]=1; 210 ++bcc_cnt; 211 do 212 { 213 k=st[top--]; 214 T.add(k,bcc_cnt); 215 UN(bcc_cnt,k); 216 }while(k!=v); 217 T.add(u,bcc_cnt); 218 UN(u,bcc_cnt); 219 } 220 } 221 else 222 if(v!=f) 223 low[u]=min(low[u],dfn[v]); 224 } 225 } 226 int main() 227 { 228 read(n); 229 read(m); 230 read(q); 231 int u,v,i,j; 232 for(i=1;i<=n;i++) 233 read(s[i]); 234 for(i=1;i<=m;i++) 235 { 236 read(u); 237 read(v); 238 add(u,v); 239 } 240 bcc_cnt=n; 241 tarjan(1,0); 242 for(i=1;i<=n;i++) 243 if(cut[i]) 244 for(j=pr[i];j;j=e[j].nex) 245 if(cut[e[j].v]&&find_fa(i)!=find_fa(e[j].v)) 246 { 247 ++bcc_cnt; 248 T.add(i,bcc_cnt); 249 T.add(e[j].v,bcc_cnt); 250 } 251 T.init(); 252 char op[2]; 253 for(i=1;i<=q;i++) 254 { 255 scanf("%s",op); 256 read(u); 257 read(v); 258 if(op[0]=='A') 259 printf("%d\n",T.query(u,v)); 260 else 261 T.change(u,v); 262 } 263 }
偏偏出现在最后的补充说明:
如果两个点的LCA是一个新建结点,那LCA的fa也是一个属于该点的割点,修改时也要修改。