[bzoj1969][AHOI2005]LANE 航线规划
2016-08-18 21:44
411 查看
题目大意
一个n个节点m条边的图,两点间的关键边定义为从一点走到另一个点必须经过的边。现有许多操作,删一条边或者询问两点间的关键边数量。
保证任意时刻原图联通。
时间倒流
先把所有边删掉,然后倒着做,转删边为加边。然后我们思考,最后原图也是联通的,那么做边双联通分量缩点后,就会变成一棵树。
然后显然两个结点间关键边数等于它们所处联通分量代表的点在树上树路径的边数。
然而我们要处理加边,每加一条边产生一个环,例如j与k(j与k指树中节点)间添加一条边,那么j到k路径上的所有点都处在一个环中,自然的,j到k路径上的所有边绝对不可能是关键边。
于是边给个边权,1代表是关建边0代表不是。
询问就是询问树中路径边权和,树链剖分维护。
修改就是路径上的边都赋值为0。
注意各种细节。。
怎么我代码那么丑写了230+行,陈主力比我少100行。
#include<cstdio> #include<algorithm> #include<map> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second using namespace std; typedef pair<int,int> suan; map<suan,int> pos,sop; const int maxn=30000+10,maxm=100000+10; int fa[maxn][20],d[maxn]; int h[maxn],belong[maxn],s[maxn],dfn[maxn],low[maxn],from[maxm*2],go[maxm*2],next[maxm*2]; int size[maxn],jump[maxn]; int h2[maxn],g2[maxn*2],n2[maxn*2]; int q[maxn*2][4]; int tree[maxn*4],set[maxn*4]; bool bz[maxm],zb[maxm],pd[maxn],flag[maxn],bj[maxn*4]; int i,j,k,l,t,n,m,tot,top,cnt,num,sum,euler; void add(int x,int y){ pos[make_pair(x,y)]=++tot; go[tot]=y; from[tot]=x; next[tot]=h[x]; h[x]=tot; } void add2(int x,int y){ g2[++sum]=y; n2[sum]=h2[x]; h2[x]=sum; } void tarjan(int x){ dfn[x]=low[x]=++euler; s[++top]=x; pd[x]=1; flag[x]=1; int t=h[x]; while (t){ if (!bz[(t+1)/2]&&!zb[(t+1)/2]){ zb[(t+1)/2]=1; if (pd[go[t]]){ if (flag[go[t]]) low[x]=min(low[x],dfn[go[t]]); } else{ tarjan(go[t]); low[x]=min(low[x],low[go[t]]); } } t=next[t]; } if (dfn[x]==low[x]){ num++; do{ belong[s[top]]=num; flag[s[top]]=0; top--; }while (s[top+1]!=x); } } void dfs(int x,int y){ fa[x][0]=y; d[x]=d[y]+1; int t=h2[x]; size[x]=1; while (t){ if (g2[t]!=y){ dfs(g2[t],x); size[x]+=size[g2[t]]; } t=n2[t]; } } void dg(int x,int y){ dfn[x]=++euler; int t=h2[x],j=0; while (t){ if (g2[t]!=y&&(j==0||size[g2[t]]>size[j])) j=g2[t]; t=n2[t]; } if (j){ jump[j]=jump[x]; dg(j,x); } t=h2[x]; while (t){ if (g2[t]!=y&&g2[t]!=j){ jump[g2[t]]=g2[t]; dg(g2[t],x); } t=n2[t]; } } int lca(int x,int y){ if (d[x]<d[y]) swap(x,y); if (d[x]!=d[y]){ int j=floor(log(num)/log(2)); while (j>=0){ if (d[fa[x][j]]>=d[y]) x=fa[x][j]; j--; } } if (x==y) return x; int j=floor(log(num)/log(2)); while (j>=0){ if (fa[x][j]!=fa[y][j]){ x=fa[x][j]; y=fa[y][j]; } j--; } return fa[x][0]; } void mark(int p,int l,int r,int v){ tree[p]=(r-l+1)*v; bj[p]=1; set[p]=v; } void down(int p,int l,int r){ int mid=(l+r)/2; if (bj[p]){ mark(p*2,l,mid,set[p]); mark(p*2+1,mid+1,r,set[p]); bj[p]=0; } } void change(int p,int l,int r,int a,int b,int v){ if (l==a&&r==b){ mark(p,l,r,v); return; } down(p,l,r); int mid=(l+r)/2; if (b<=mid) change(p*2,l,mid,a,b,v); else if (a>mid) change(p*2+1,mid+1,r,a,b,v); else{ change(p*2,l,mid,a,mid,v); change(p*2+1,mid+1,r,mid+1,b,v); } tree[p]=tree[p*2]+tree[p*2+1]; } int query(int p,int l,int r,int a,int b){ if (l==a&&r==b) return tree[p]; down(p,l,r); int mid=(l+r)/2; if (b<=mid) return query(p*2,l,mid,a,b); else if (a>mid) return query(p*2+1,mid+1,r,a,b); else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b); } int main(){ freopen("data.in","r",stdin);freopen("data.out","w",stdout); scanf("%d%d",&n,&m); fo(i,1,m){ scanf("%d%d",&j,&k); add(j,k); add(k,j); } while (1){ scanf("%d",&q[++cnt][0]); if (q[cnt][0]==-1) break; scanf("%d%d",&q[cnt][1],&q[cnt][2]); if (!q[cnt][0]) bz[(pos[make_pair(q[cnt][1],q[cnt][2])]+1)/2]=1; } cnt--; tarjan(1); fo(i,1,tot) if (!bz[(i+1)/2]&&belong[from[i]]!=belong[go[i]]){ j=belong[from[i]];k=belong[go[i]]; if (j>k) swap(j,k); if (!sop[make_pair(j,k)]){ sop[make_pair(j,k)]=1; add2(j,k); add2(k,j); } } dfs(1,0); fo(j,1,floor(log(num)/log(2))) fo(i,1,num) fa[i][j]=fa[fa[i][j-1]][j-1]; euler=0; dg(1,0); fo(i,2,num) change(1,1,num,dfn[i],dfn[i],1); fd(i,cnt,1){ j=belong[q[i][1]];k=belong[q[i][2]]; if (j==k) continue; l=lca(j,k); if (q[i][0]==0){ while (j!=l){ if (d[jump[j]]<=d[l]){ change(1,1,num,dfn[l]+1,dfn[j],0); j=l; } else{ change(1,1,num,dfn[jump[j]],dfn[j],0); j=fa[jump[j]][0]; } } while (k!=l){ if (d[jump[k]]<=d[l]){ change(1,1,num,dfn[l]+1,dfn[k],0); k=l; } else{ change(1,1,num,dfn[jump[k]],dfn[k],0); k=fa[jump[k]][0]; } } } else{ while (j!=l){ if (d[jump[j]]<=d[l]){ q[i][3]+=query(1,1,num,dfn[l]+1,dfn[j]); j=l; } else{ q[i][3]+=query(1,1,num,dfn[jump[j]],dfn[j]); j=fa[jump[j]][0]; } } while (k!=l){ if (d[jump[k]]<=d[l]){ q[i][3]+=query(1,1,num,dfn[l]+1,dfn[k]); k=l; } else{ q[i][3]+=query(1,1,num,dfn[jump[k]],dfn[k]); k=fa[jump[k]][0]; } } } } fo(i,1,cnt) if (q[i][0]) printf("%d\n",q[i][3]); }
相关文章推荐
- [bzoj1969] [Ahoi2005]LANE 航线规划
- 【BZOJ1969】[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
- 【BZOJ 1969】【AHOI 2005】LANE 航线规划【离线、hash、并查集、树链剖分、线段树】
- [BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分)
- BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]
- bzoj 1969: [Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
- bzoj 1969: [Ahoi2005]LANE 航线规划(树链剖分+线段树+最小生成树)
- 【动态缩点】【bzoj 1969】: [Ahoi2005]LANE 航线规划
- [AHOI2005]【bzoj1969】LANE 航线规划——LCT维护双联通分量
- ●BZOJ 1969 [Ahoi2005]LANE 航线规划
- [BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分+并查集)
- Bzoj1969: [Ahoi2005]LANE 航线规划
- Bzoj1969: [Ahoi2005]LANE 航线规划
- 【AHOI2005】【BZOJ1969】LANE 航线规划
- 【BZOJ】1969: [Ahoi2005]LANE 航线规划
- bzoj 1969: [Ahoi2005]LANE 航线规划
- 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)
- BZOJ 1969: [Ahoi2005]LANE 航线规划
- [BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分+并查集)
- BZOJ 线段树 1969: [Ahoi2005]LANE 航线规划