[AHOI2005]航线规划(树链剖分+时间倒流)

Posted yyys-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AHOI2005]航线规划(树链剖分+时间倒流)相关的知识,希望对你有一定的参考价值。

传送门

练一下树剖的板子,运用一下时间倒流和下放边权的思想。

题中所谓“关键航线”其实就是桥。

删边操作桥不好维护,但如果是加边,每加一条边,两点作为端点的这条路径就都不再是桥----->考虑时间倒流。

从后往前,每删除一条边,现在就是加边,该路径上所有边都不是桥(打上标记)。

可以先求出一棵最小生成树(代码中是在dfs中实现的)那些多的边就以加边的方式加入(说明到最后一个操作后,这条路径的边也不是桥)。

技术图片
#include<bits/stdc++.h>
#define M 200003
#define N 60003
using namespace std;
int read()

    int x=0,f=1;char s=getchar();
    while(s<0||s>9)if(s==-)f=-1;s=getchar();
    while(s>=0&&s<=9)x=x*10+s-0;s=getchar();
    return x*f;  

map<pair<int,int>,int>ma;
int fa[N],top[N],siz[N],head[N],dep[N],vis[N],son[N],pos[N];
int sum[N<<2],mark[N<<2],n;
struct EDGE
    int nextt,to,del,used;
w[M*4];
struct Q
    int x,y,op,ans;
q[M];
int tot=1;
void add(int a,int b)

    tot++;
    w[tot].nextt=head[a];
    w[tot].to=b;
    head[a]=tot;

void dfs1(int x)

    vis[x]=1;//用vis,因为可能有环 
    siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i;i=w[i].nextt)
    
        int v=w[i].to;
        if(vis[v]||w[i].del)continue;
        fa[v]=x;dep[v]=dep[x]+1;
        w[i].used=1;w[i^1].used=1;//在dfs中处理出最小生成树 
        dfs1(v);
        siz[x]+=siz[v];
        if(maxson<siz[v])son[x]=v,maxson=siz[v];
    

int cnt=0;
void dfs2(int x,int topf)

    vis[x]=1;
    pos[x]=++cnt;
    top[x]=topf;
    if(!son[x])return;
    dfs2(son[x],topf);
    for(int i=head[x];i;i=w[i].nextt)
    
        int v=w[i].to;
        if(vis[v]||v==son[x]||w[i].del)continue;
        dfs2(v,v);
    

void build(int k,int l,int r)

    if(l==r)
    
        sum[k]=1;
        return;
    
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];

void pushdown(int k,int l,int r)

    if(!mark[k])return;
    mark[k<<1]=mark[k<<1|1]=1;
    sum[k<<1]=sum[k<<1|1]=0;
    mark[k]=0;

void modify(int k,int L,int R,int l,int r)

    if(L>=l&&R<=r)
    
        sum[k]=0;
        mark[k]=1;
        return;
    
    int mid=(L+R)>>1;
    pushdown(k,L,R);
    if(l<=mid)modify(k<<1,L,mid,l,r);
    if(r>mid)modify(k<<1|1,mid+1,R,l,r);
    sum[k]=sum[k<<1|1]+sum[k<<1];

void range(int x,int y)

    while(top[x]!=top[y])
    
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        modify(1,1,n,pos[top[x]],pos[x]);
        x=fa[top[x]];
    
    if(dep[x]>dep[y])swap(x,y);
    modify(1,1,n,pos[x]+1,pos[y]);//下放边权,注意lca的位置 

int query(int k,int L,int R,int l,int r)

    int res=0;
    if(L>=l&&R<=r)return sum[k];
    int mid=(L+R)>>1;
    pushdown(k,L,R);
    if(l<=mid)res+=query(k<<1,L,mid,l,r);
    if(r>mid)res+=query(k<<1|1,mid+1,R,l,r);
    return res;

int querysum(int x,int y)

    int res=0;
    while(top[x]!=top[y])
    
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        res+=query(1,1,n,pos[top[x]],pos[x]);
        x=fa[top[x]];
    
    if(dep[x]>dep[y])swap(x,y);
    res+=query(1,1,n,pos[x]+1,pos[y]);
    return res;

int main()

    n=read();int m=read();
    for(int i=1;i<=m;++i)
    
        int a=read(),b=read();
        if(a>b)swap(a,b);
        add(a,b);add(b,a);
        ma[make_pair(a,b)]=i;
    
    int c=read();
    int ge=0;
    while(c!=-1)
    
        int a=read(),b=read();
        if(a>b)swap(a,b);
        q[++ge].op=c;
        q[ge].x=a;q[ge].y=b;
        if(c==0)
        
            int id=ma[make_pair(a,b)];
            w[id*2].del=1;w[id*2+1].del=1;
        
        c=read();
    
    dep[1]=1;
    dfs1(1);
    memset(vis,0,sizeof(vis));
    dfs2(1,1);
    build(1,1,n);
    for(int i=2;i<=tot;i+=2)
    
        if(w[i].del||w[i].used)continue;
        range(w[i].to,w[i^1].to);    
    
    for(int i=ge;i>=1;--i)
    
        if(q[i].op==0)range(q[i].x,q[i].y);
        else q[i].ans=querysum(q[i].x,q[i].y);
    
    for(int i=1;i<=ge;++i)
      if(q[i].op==1)printf("%d\n",q[i].ans);
 
View Code

 

以上是关于[AHOI2005]航线规划(树链剖分+时间倒流)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Luogu2542 AHOI2005 航线规划 树链剖分线段树

bzoj1969 [Ahoi2005]LANE 航线规划 树链剖分

bzoj1959[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

[bzoj1969] [Ahoi2005]LANE 航线规划