zoukankan      html  css  js  c++  java
  • [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
    ",ans[i]);
    }
    View Code
  • 相关阅读:
    路由的配置,侧边栏类名与url的结合运用
    bootstrap面包屑在ie8下显示重叠,鼠标点击显示效果正常
    JS代码判断IE6,IE7,IE8,IE9!
    wampserver配置服务
    HTML5 20180918----20180921
    HTML5 20180921
    HTML5 20180920
    HTML5 20180919
    HTML5 20180918
    HTTP协议
  • 原文地址:https://www.cnblogs.com/sto324/p/11345140.html
Copyright © 2011-2022 走看看