[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);
以上是关于[AHOI2005]航线规划(树链剖分+时间倒流)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )
BZOJ1969[Ahoi2005]LANE 航线规划 离线+树链剖分+线段树
Luogu2542 AHOI2005 航线规划 树链剖分线段树
bzoj1969 [Ahoi2005]LANE 航线规划 树链剖分