[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]);
View Code

 

以上是关于[AHOI2005]航线规划的主要内容,如果未能解决你的问题,请参考以下文章

解题:AHOI 2005 航线规划

BZOJ1969[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树

刷题BZOJ 1969 [Ahoi2005]LANE 航线规划

BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

BZOJ1969: [Ahoi2005]LANE 航线规划(LCT)

[AHOI2005]航线规划