[bzoj1969][AHOI2005]LANE 航线规划

题目大意

一个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]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值