[AHOI2005]航线规划
Posted sto324
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AHOI2005]航线规划相关的知识,希望对你有一定的参考价值。
题意
给一个n个点m条边的图,有两种操作:询问x到y的路径必经的边有几条,删除x,y之间的直接连边。
1< N < 30000,1 < M < 100000,操作总数不超过40000
我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。
题解
必经边就是桥(删去x,y不连通那种),但是不好维护。因为无论什么时候两点连通,所以考虑特殊情况:一棵树,树边都是必经边,考虑加边会带来什么影响,会导致树上x到y的路径都不是必经边,当然加进来的边也不是。所以就很好维护了,考虑时光倒流,先用没摧毁的边建一棵树,加边就是路径修改,查询就是路径查询,用树剖就可以了。那些没摧毁的非树边就按照路径修改加进来就可以了。
找摧毁的是哪条边有点恶心(也有可能我写的方法不对),看见有用hash的。
还有就是因为是路径,所以把值赋给儿子节点的话,查询和修改时最后应该是id[x]+1
#include<bits/stdc++.h> using namespace std; const int maxn=40005; const int maxm=100005; int n,m,cnt,num; int fa[maxn]; bool broken[maxm];//broken 1:没用到的没炸的边 int dep[maxn],size[maxn],son[maxn],id[maxn],top[maxn]; int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1]; int tot,ans[maxn]; vector<int>cx[maxn]; struct edge int x,y; e[maxm]; struct question int op,x,y,id; q[maxn]; template<class T>inline void read(T &x) x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) f|=(ch==‘-‘);ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48);ch=getchar(); x= f ? -x : x ; bool cmp(edge a,edge b) if(a.x==b.x) return a.y<b.y; return a.x<b.x; bool cmp1(question a,question b) if(a.op!=b.op) return a.op<b.op; if(a.x==b.x) return a.y<b.y; return a.x<b.x; bool cmp2(question a,question b) return a.id>b.id; int find(int x) return fa[x]==x ? x : fa[x]=find(fa[x]); void connect(int x,int y,int i) int dx=find(x),dy=find(y); if(dx!=dy) cx[x].push_back(y); cx[y].push_back(x); fa[dx]=dy; else broken[i]=true; void dfs(int u) size[u]=1; for(unsigned int i=0;i<cx[u].size();i++) int v=cx[u][i]; if(v==fa[u]) continue; fa[v]=u; dep[v]=dep[u]+1; dfs(v); size[u]+=size[v]; if(size[son[u]]<size[v]) son[u]=v; void dfs(int u,int tp) id[u]=++num; top[u]=tp; if(!son[u]) return ; dfs(son[u],tp); for(unsigned int i=0;i<cx[u].size();i++) int v=cx[u][i]; if(v==fa[u]||v==son[u]) continue; dfs(v,v); void update(int rt) sum[rt]=sum[ls[rt]]+sum[rs[rt]]; void build(int &rt,int l,int r) rt=++num; if(l==r) sum[rt]=1; return ; int mid=(l+r)>>1; build(ls[rt],l,mid); build(rs[rt],mid+1,r); update(rt); void modify(int rt,int l,int r,int a_l,int a_r) if(!sum[rt]) return ; if(a_l<=l&&r<=a_r) sum[rt]=0; return ; int mid=(l+r)>>1; if(a_l<=mid) modify(ls[rt],l,mid,a_l,a_r); if(mid<a_r) modify(rs[rt],mid+1,r,a_l,a_r); update(rt); void modify(int x,int y) while(top[x]!=top[y]) if(dep[top[x]]>dep[top[y]]) swap(x,y); modify(1,1,n,id[top[y]],id[y]); y=fa[top[y]]; if(dep[x]>dep[y]) swap(x,y); modify(1,1,n,id[x]+1,id[y]); int query(int rt,int l,int r,int a_l,int a_r) if(!sum[rt]) return sum[rt]; if(a_l<=l&&r<=a_r) return sum[rt]; int mid=(l+r)>>1; int ret=0; if(a_l<=mid) ret+=query(ls[rt],l,mid,a_l,a_r); if(mid<a_r) ret+=query(rs[rt],mid+1,r,a_l,a_r); return ret; int query(int x,int y) int ret=0; while(top[x]!=top[y]) if(dep[top[x]]>dep[top[y]]) swap(x,y); ret+=query(1,1,n,id[top[y]],id[y]); y=fa[top[y]]; if(dep[x]>dep[y]) swap(x,y); ret+=query(1,1,n,id[x]+1,id[y]); return ret; int main() read(n);read(m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) read(e[i].x);read(e[i].y); if(e[i].x>e[i].y) swap(e[i].x,e[i].y); while(1) read(q[++cnt].op); if(q[cnt].op==-1) cnt--;break; read(q[cnt].x); read(q[cnt].y); q[cnt].id=cnt; if(q[cnt].x>q[cnt].y) swap(q[cnt].x,q[cnt].y); sort(e+1,e+m+1,cmp); sort(q+1,q+cnt+1,cmp1); for(int i=1,j=1;;j++) while(j<=cnt&&!q[j].op&&i<=m&&(q[j].x!=e[i].x||q[j].y!=e[i].y)) connect(e[i].x,e[i].y,i),i++; if(i>m) break; if(j>cnt||q[j].op) connect(e[i].x,e[i].y,i); i++; memset(fa,0,sizeof(fa)); dep[1]=1; dfs(1); dfs(1,1); num=0; build(root,1,n); for(int i=1;i<=m;i++) if(broken[i]) modify(e[i].x,e[i].y); sort(q+1,q+cnt+1,cmp2); for(int i=1;i<=cnt;i++) if(!q[i].op) modify(q[i].x,q[i].y); else ans[++tot]=query(q[i].x,q[i].y); for(int i=tot;i;i--) printf("%d\n",ans[i]);
以上是关于[AHOI2005]航线规划的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1969[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
刷题BZOJ 1969 [Ahoi2005]LANE 航线规划
BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )