[BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分+并查集)
2016-09-24 11:27
393 查看
题目描述
传送门题解
删边不好删,那么就反向加边。这种思路在星球大战那道题里遇到过。因为任意时刻所有的点连通,那么它至少是一棵树。可以先建出一棵树来。那么st之间的关键路径只可能是s到t树链上的边。那么可以枚举非树边,非树边以及它两个端点组成的树链一定成环,并且这个环上的每一条边都不可能是关键边。这样动态维护一下就行了。
值得注意的是树链剖分维护边权将边权下放成点权。这样的话当两个点到达一条重链的时候应该将深度小的那个点变成它的重儿子,也就是编号+1。我刚开始没有考虑到有一些点没有重儿子,直接wa挺了。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<map> using namespace std; #define N 30005 #define M 100005 #define C 40005 struct hp{int x,y;}edge[M],not_tree[M]; int n,m,q,t,opt[C],x[C],y[C],sum[N*4],delta[N*4],ans[C]; int f ,size ,h ,father ,son ,top ,num ,dfs_clock; int tot,point ,nxt[M*2],v[M*2]; map <int,bool> hash; int find(int x) { if (x==f[x]) return x; f[x]=find(f[x]); return f[x]; } void addedge(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs_1(int x,int fa,int dep) { size[x]=1; father[x]=fa; h[x]=dep; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { dfs_1(v[i],x,dep+1); size[x]+=size[v[i]]; if (size[v[i]]>size[son[x]]) son[x]=v[i]; } } void dfs_2(int x,int fa) { if (son[fa]==x) top[x]=top[fa]; else top[x]=x; num[x]=++dfs_clock; if (son[x]) dfs_2(son[x],x); for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa&&v[i]!=son[x]) dfs_2(v[i],x); } void update(int now) { sum[now]=sum[now<<1]+sum[now<<1|1]; } void pushdown(int now,int l,int r,int mid) { if (delta[now]!=-1) { sum[now<<1]=sum[now<<1|1]=delta[now<<1]=delta[now<<1|1]=delta[now]; delta[now]=-1; } } void build(int now,int l,int r) { int mid=(l+r)>>1; delta[now]=-1; if (l==r) { sum[now]=1; if (l==1) sum[now]=0; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now); } void interval_change(int now,int l,int r,int lrange,int rrange) { int mid=(l+r)>>1; if (lrange<=l&&r<=rrange) { sum[now]=0; delta[now]=0; return; } pushdown(now,l,r,mid); if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange); update(now); } int query(int now,int l,int r,int lrange,int rrange) { int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return sum[now]; pushdown(now,l,r,mid); if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange); return ans; } void change(int u,int t) { int f1=top[u],f2=top[t]; while (f1!=f2) { if (h[f1]<h[f2]) { swap(f1,f2); swap(u,t); } interval_change(1,1,n,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); if (num[u]+1<=num[t]) interval_change(1,1,n,num[u]+1,num[t]); } int ask(int u,int t) { int f1=top[u],f2=top[t],ans=0; while (f1!=f2) { if (h[f1]<h[f2]) { swap(f1,f2); swap(u,t); } ans+=query(1,1,n,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); if (num[u]+1<=num[t]) ans+=query(1,1,n,num[u]+1,num[t]); return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;++i) { scanf("%d%d",&edge[i].x,&edge[i].y); if (edge[i].x>edge[i].y) swap(edge[i].x,edge[i].y); } while (1) { scanf("%d",&opt[++q]); if (opt[q]==-1) break; scanf("%d%d",&x[q],&y[q]); if (x[q]>y[q]) swap(x[q],y[q]); if (opt[q]==0) { int now=(x[q]-1)*n+y[q]; hash[now]=true; } } for (int i=1;i<=n;++i) f[i]=i; for (int i=1;i<=m;++i) { int now=(edge[i].x-1)*n+edge[i].y; if (hash[now]) continue; int f1=find(edge[i].x),f2=find(edge[i].y); if (f1!=f2) { addedge(edge[i].x,edge[i].y); f[f1]=f2; } else not_tree[++t].x=edge[i].x,not_tree[t].y=edge[i].y; } dfs_1(1,0,1); dfs_2(1,0); build(1,1,n); for (int i=1;i<=t;++i) change(not_tree[i].x,not_tree[i].y); for (int i=q-1;i>=1;--i) if (opt[i]==0) change(x[i],y[i]); else ans[i]=ask(x[i],y[i]); for (int i=1;i<q;++i) if (opt[i]) printf("%d\n",ans[i]); }
手工栈
#include<iostream> #include<cstring> #include<cstdio> #include<map> using namespace std; #define N 30005 #define M 100005 #define C 40005 struct hp{int x,y;}edge[M],not_tree[M]; int n,m,q,t,opt[C],x[C],y[C],sum[N*4],delta[N*4],ans[C]; int f ,size ,h ,father ,son ,top ,num ,dfs_clock; int tot,point ,nxt[M*2],v[M*2]; map <int,bool> hash; int stack ,cur ;bool use ; int find(int x) { if (x==f[x]) return x; f[x]=find(f[x]); return f[x]; } void addedge(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs_1() { int tmp=0; stack[++tmp]=1;h[1]=1;size[1]=1; for (int i=1;i<=n;++i) cur[i]=point[i]; while (tmp) { int x=stack[tmp]; if (cur[x]&&v[cur[x]]==father[x]) cur[x]=nxt[cur[x]]; if (!cur[x]) { --tmp; if (father[x]) { size[father[x]]+=size[x]; if (size[x]>size[son[father[x]]]) son[father[x]]=x; } continue; } int vt=v[cur[x]]; stack[++tmp]=vt; h[vt]=h[x]+1;size[vt]=1;father[vt]=x; cur[x]=nxt[cur[x]]; } } void dfs_2() { int tmp=0; stack[++tmp]=1;num[1]=++dfs_clock;top[1]=1; for (int i=1;i<=n;++i) cur[i]=point[i]; while (tmp) { int x=stack[tmp]; if (!use[x]) { use[x]=1; int vt=son[x]; if (vt) { stack[++tmp]=vt; num[vt]=++dfs_clock; top[vt]=top[x]; } continue; } while (cur[x]&&(v[cur[x]]==father[x]||v[cur[x]]==son[x])) cur[x]=nxt[cur[x]]; if (!cur[x]) { --tmp; continue; } else { int vt=v[cur[x]]; stack[++tmp]=vt; num[vt]=++dfs_clock; top[vt]=vt; cur[x]=nxt[cur[x]]; } } } void update(int now) { sum[now]=sum[now<<1]+sum[now<<1|1]; } void pushdown(int now,int l,int r,int mid) { if (delta[now]!=-1) { sum[now<<1]=sum[now<<1|1]=delta[now<<1]=delta[now<<1|1]=delta[now]; delta[now]=-1; } } void build(int now,int l,int r) { int mid=(l+r)>>1; delta[now]=-1; if (l==r) { sum[now]=1; if (l==1) sum[now]=0; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now); } void interval_change(int now,int l,int r,int lrange,int rrange) { int mid=(l+r)>>1; if (lrange<=l&&r<=rrange) { sum[now]=0; delta[now]=0; return; } pushdown(now,l,r,mid); if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange); update(now); } int query(int now,int l,int r,int lrange,int rrange) { int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return sum[now]; pushdown(now,l,r,mid); if (lrange<=mid) ans+=query(now<<1,l,mid,lrange,rrange); if (mid+1<=rrange) ans+=query(now<<1|1,mid+1,r,lrange,rrange); return ans; } void change(int u,int t) { int f1=top[u],f2=top[t]; while (f1!=f2) { if (h[f1]<h[f2]) { swap(f1,f2); swap(u,t); } interval_change(1,1,n,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); if (num[u]+1<=num[t]) interval_change(1,1,n,num[u]+1,num[t]); } int ask(int u,int t) { int f1=top[u],f2=top[t],ans=0; while (f1!=f2) { if (h[f1]<h[f2]) { swap(f1,f2); swap(u,t); } ans+=query(1,1,n,num[f1],num[u]); u=father[f1]; f1=top[u]; } if (num[u]>num[t]) swap(u,t); if (num[u]+1<=num[t]) ans+=query(1,1,n,num[u]+1,num[t]); return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;++i) { scanf("%d%d",&edge[i].x,&edge[i].y); if (edge[i].x>edge[i].y) swap(edge[i].x,edge[i].y); } while (1) { scanf("%d",&opt[++q]); if (opt[q]==-1) break; scanf("%d%d",&x[q],&y[q]); if (x[q]>y[q]) swap(x[q],y[q]); if (opt[q]==0) { int now=(x[q]-1)*n+y[q]; hash[now]=true; } } for (int i=1;i<=n;++i) f[i]=i; for (int i=1;i<=m;++i) { int now=(edge[i].x-1)*n+edge[i].y; if (hash[now]) continue; int f1=find(edge[i].x),f2=find(edge[i].y); if (f1!=f2) { addedge(edge[i].x,edge[i].y); f[f1]=f2; } else not_tree[++t].x=edge[i].x,not_tree[t].y=edge[i].y; } dfs_1(); dfs_2(); build(1,1,n); for (int i=1;i<=t;++i) change(not_tree[i].x,not_tree[i].y); for (int i=q-1;i>=1;--i) if (opt[i]==0) change(x[i],y[i]); else ans[i]=ask(x[i],y[i]); for (int i=1;i<q;++i) if (opt[i]) printf("%d\n",ans[i]); }
总结
①树链剖分边权下放成点权以后不能出错了。相关文章推荐
- [BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分+并查集)
- 【动态缩点】【bzoj 1969】: [Ahoi2005]LANE 航线规划
- [AHOI2005]【bzoj1969】LANE 航线规划——LCT维护双联通分量
- ●BZOJ 1969 [Ahoi2005]LANE 航线规划
- Bzoj1969: [Ahoi2005]LANE 航线规划
- 【AHOI2005】【BZOJ1969】LANE 航线规划
- Bzoj1969: [Ahoi2005]LANE 航线规划
- bzoj 1969: [Ahoi2005]LANE 航线规划
- 【BZOJ】1969: [Ahoi2005]LANE 航线规划
- 【BZOJ 1969】 1969: [Ahoi2005]LANE 航线规划 (树链剖分+线段树)
- BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )
- BZOJ 1969: [Ahoi2005]LANE 航线规划
- BZOJ 线段树 1969: [Ahoi2005]LANE 航线规划
- [bzoj1969] [Ahoi2005]LANE 航线规划
- 【BZOJ1969】[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
- 【BZOJ 1969】【AHOI 2005】LANE 航线规划【离线、hash、并查集、树链剖分、线段树】
- [BZOJ1969][Ahoi2005]LANE 航线规划(树链剖分)
- BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]
- bzoj 1969: [Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
- [bzoj1969][AHOI2005]LANE 航线规划