P4949 最短距离
神仙黑题
盗图
基环树带修改求距离
1.环上线段树,树上用树剖
代码:(只有90分)
#includeusing namespace std; #define il inline const int N=510010; int n,m; struct node{ int from,to,val; int expet; }s[N]; int hed[N]={0},tal[N<<1]={0},val[N<<1]={0},nxt[N<<1]={0},cnt=0; int fake_fa[N]={0};//假父亲 int fa[N]={0};//真·父亲 bool vis[N]={0}; bool flag=0; bool is_cir[N]={0};//判断点是否在环上 int upy=0; int root[N]={0}; int dep[N]={0};//深度 int size[N]={0}; int son[N]={0}; int top[N]={0}; int indexy=0; int dfn[N]={0}; int rk[N]={0}; int v[N]={0}; int cir_node[N]={0};//环上的点编号 int anycount=0; int belong[N]; int CIR=0; int ith[N]; int vanu[N]={0}; struct Sugment_Tree{ int t[N<<2]; #define mid (l+r)/2 Sugment_Tree(){ memset(t,0,sizeof(t)); } il void push_up(int num){ t[num]=t[num<<1]+t[num<<1|1]; } il void build(int l,int r,int num){ if(l==r){ t[num]=v[l]; return; } build(l,mid,num<<1); build(mid+1,r,num<<1|1); push_up(num); } il void rebuild(int l,int r,int num){ if(l==r){ t[num]=vanu[l]; return; } rebuild(l,mid,num<<1); rebuild(mid+1,r,num<<1|1); push_up(num); } il void upd(int l,int r,int num,int pos,int SUM){ if(l>pos||r return; // cout< if(l==r){ t[num]=SUM; return; } upd(l,mid,num<<1,pos,SUM); upd(mid+1,r,num<<1|1,pos,SUM); push_up(num); } il int ask(int l,int r,int num,int L,int R){ if(l>R||r 0; if(l>=L&&r<=R) return t[num]; return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R); } }T,P; il void addege(int x,int y,int z){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; hed[x]=cnt; } il void dfs_find(int x){ if(is_cir[x]==1) return; anycount++; cir_node[x]=anycount; ith[anycount]=x; is_cir[x]=1; dfs_find(fake_fa[x]); } il void dfs_cir(int u,int fa){ if(flag==1) return; fake_fa[u]=fa; vis[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa) continue; if(vis[v]){ flag=1; dfs_find(u);//导出环 } else{ dfs_cir(v,u); } } } il void dfs_tree(int u,int fat){ fa[u]=fat; size[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fat||is_cir[v]) continue; dep[v]=dep[u]+1; belong[v]=belong[u]; dfs_tree(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } il void dfs2(int u,int tp){ top[u]=tp; ++indexy; dfn[u]=indexy; rk[dfn[u]]=u; if(!son[u]) return; dfs2(son[u],tp); for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa[u]||v==son[u]||is_cir[v]) continue; dfs2(v,v); } } il int cgn(int x,int y){ int sum=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); sum+=T.ask(1,n,1,dfn[top[x]],dfn[x]); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); sum+=T.ask(1,n,1,dfn[y]+1,dfn[x]); return sum; } il int kan(int x,int y){ int sum1=0,sum2=0; if(cir_node[x]>cir_node[y]) swap(x,y); //y=ith[cir_node[y]-1]; // cout<return // cout< if(cir_node[x]>cir_node[y]-1) return 0; sum1=P.ask(1,anycount,1,cir_node[x],cir_node[y]-1); //cout< sum2=CIR-sum1; return min(sum1,sum2); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); s[i].from=x,s[i].to=y,s[i].val=z; addege(x,y,z); addege(y,x,z); } dfs_cir(1,1);//找环 // for(int i=1;i<=n;i++){//check // if(is_cir[i]) printf("%d ",i); // } // printf("\n"); //环上的点作为子树的根 for(int i=1;i<=n;i++){ if(is_cir[i]){ belong[i]=i; dep[i]=1; upy++; root[upy]=i; dfs_tree(i,i); } } // for(int i=1;i<=n;i++){//check // printf("%d ** %d\n",fa[i],son[i]); // } // printf("\n"); // for(int i=1;i<=n;i++){ // printf("%d ",cir_node[i]); // } // printf("\n"); for(int i=1;i<=upy;i++){ dfs2(root[i],root[i]); } // cout< // for(int i=1;i<=n;i++) printf("%d ",dfn[i]);//check // printf("\n"); for(int i=1;i<=n;i++){ if(is_cir[s[i].from]&&is_cir[s[i].to]){ CIR+=s[i].val; if((cir_node[s[i].from]==anycount&&cir_node[s[i].to]==1)||(cir_node[s[i].from]==1&&cir_node[s[i].to]==anycount)){ continue; } if(cir_node[s[i].from]>cir_node[s[i].to]){ s[i].expet=cir_node[s[i].to],vanu[cir_node[s[i].to]]=s[i].val; } else s[i].expet=cir_node[s[i].from],vanu[cir_node[s[i].from]]=s[i].val; } else{ if(fa[s[i].from]==s[i].to) s[i].expet=dfn[s[i].from],v[dfn[s[i].from]]=s[i].val; else s[i].expet=dfn[s[i].to],v[dfn[s[i].to]]=s[i].val; } } // for(int i=1;i<=n;i++){ // cout< // } // cout< T.build(1,n,1); P.rebuild(1,anycount,1); // cout< //cout< for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); if(x==1){ if(is_cir[s[y].from]&&is_cir[s[y].to]){ CIR-=s[y].val; s[y].val=z; CIR+=s[y].val; if((cir_node[s[y].from]==anycount&&cir_node[s[y].to]==1)||(cir_node[s[y].from]==1&&cir_node[s[y].to]==anycount)){ continue; } //cout< // cout< P.upd(1,anycount,1,s[y].expet,z); //cout< } else{ T.upd(1,n,1,s[y].expet,z); } } else{ if(belong[y]==belong[z]){ printf("%d\n",cgn(y,z)); } else{ int ans=0; ans+=cgn(y,belong[y]); ans+=cgn(z,belong[z]); //cout< ans+=kan(belong[y],belong[z]); //cout< printf("%d\n",ans); } } } return 0; }
2.选一条环上的边做特殊边
其余用树剖
代码(100分):
#includeusing namespace std; #define il inline const int N=510010; int n,m; struct node{ int from,to,val; int expet; }s[N]; int hed[N]={0},tal[N<<1]={0},val[N<<1]={0},nxt[N<<1]={0},cnt=0; int fake_fa[N]={0};//假父亲 int fa[N]={0};//真·父亲 bool vis[N]={0}; bool flag=0; int upy=0; int root[N]={0}; int dep[N]={0};//深度 int size[N]={0}; int son[N]={0}; int top[N]={0}; int indexy=0; int dfn[N]={0}; int rk[N]={0}; int CIR=0; int v[N]={0}; int jingzhix,jingzhiy,jingzhival; struct Sugment_Tree{ int t[N<<2]; #define mid (l+r)/2 Sugment_Tree(){ memset(t,0,sizeof(t)); } il void push_up(int num){ t[num]=t[num<<1]+t[num<<1|1]; } il void build(int l,int r,int num){ if(l==r){ t[num]=v[l]; return; } build(l,mid,num<<1); build(mid+1,r,num<<1|1); push_up(num); } il void upd(int l,int r,int num,int pos,int SUM){ if(l>pos||r return; // cout< if(l==r){ t[num]=SUM; return; } upd(l,mid,num<<1,pos,SUM); upd(mid+1,r,num<<1|1,pos,SUM); push_up(num); } il int ask(int l,int r,int num,int L,int R){ if(l>R||r 0; if(l>=L&&r<=R) return t[num]; return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R); } }T; il void addege(int x,int y,int z){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; val[cnt]=z; hed[x]=cnt; } il bool error(int x,int y){ if(x==jingzhix&&y==jingzhiy) return 1; if(x==jingzhiy&&y==jingzhix) return 1; return 0; } il void dfs_cir(int u,int fa){ if(flag==1) return; fake_fa[u]=fa; vis[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa) continue; if(vis[v]){ flag=1; jingzhix=u;//导出环 jingzhiy=v; jingzhival=val[i]; } else{ dfs_cir(v,u); } } } il void dfs_tree(int u,int fat){ fa[u]=fat; size[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fat) continue; if(error(u,v)) continue; dep[v]=dep[u]+1; dfs_tree(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } il void dfs2(int u,int tp){ top[u]=tp; ++indexy; dfn[u]=indexy; rk[dfn[u]]=u; if(!son[u]) return; dfs2(son[u],tp); for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa[u]||v==son[u]) continue; if(error(u,v)) continue; dfs2(v,v); } } il int cgn(int x,int y){ int sum=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); sum+=T.ask(1,n,1,dfn[top[x]],dfn[x]); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); sum+=T.ask(1,n,1,dfn[y]+1,dfn[x]); return sum; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); s[i].from=x,s[i].to=y,s[i].val=z; addege(x,y,z); addege(y,x,z); } dfs_cir(1,1);//找环 // for(int i=1;i<=n;i++){//check // if(is_cir[i]) printf("%d ",i); // } // printf("\n"); //环上的点作为子树的根 dep[1]=1; upy++; root[upy]=1; dfs_tree(1,1); dfs2(1,1); for(int i=1;i<=n;i++){ if(error(s[i].from,s[i].to)) continue; if(fa[s[i].from]==s[i].to) s[i].expet=dfn[s[i].from],v[dfn[s[i].from]]=s[i].val; else s[i].expet=dfn[s[i].to],v[dfn[s[i].to]]=s[i].val; } T.build(1,n,1); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); if(x==1){ if(error(s[y].from,s[y].to)){ jingzhival=z; } else{ T.upd(1,n,1,s[y].expet,z); } } else{ int ans1=0,ans2=0,ans3=0; ans1=cgn(y,z); ans2=cgn(y,jingzhix)+cgn(z,jingzhiy)+jingzhival; ans3=cgn(y,jingzhiy)+cgn(z,jingzhix)+jingzhival; printf("%d\n",min(ans1,min(ans2,ans3))); } } return 0; }return