[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);
} 

原文地址:https://www.cnblogs.com/yyys-/p/11335769.html

时间: 2024-10-29 05:02:55

[AHOI2005]航线规划(树链剖分+时间倒流)的相关文章

BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下,手写哈希比map快很多 貌似还有一种不用树剖的做法,不管了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; co

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

传送门 看到删边不用想就是反着加边 先把删完边之后的图拆一个生成树出来,然后考虑非树边的影响.实际上非树边就是让树上的一条路径的权值从$1$变为了$0$,而每一个询问就是一条路径上的权值之和.使用树链剖分+线段树维护权值即可. 1 #include<bits/stdc++.h> 2 #define lch (now << 1) 3 #define rch (now << 1 | 1) 4 #define mid ((l + r) >> 1) 5 //This

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

首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键边了, 因为形成了环, 环上任意2点有2条路径...下图, 加上蓝色的边, 红色x的边就变成了非关键边. 所以树链剖分维护一下...时间复杂度O(NlogN+MlogM+Qlog^2N), 可以AC. 翻了翻ZY的标解:“动态维护树+最近公共祖先查询”....复杂度是O(NlogN+M+QlogN)

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

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1969 题解 如果我们把整个图边双联通地缩点,那么最终会形成一棵树的样子. 那么在这棵树上,\(x\) 和 \(y\) 两个点的答案就是它们之间的不在环中的边的数量. 现在考虑动态维护每一条边在不在环中.发现动态删除的话不太好做,所以时光反转,改成插入一条边. 先随便建立一棵生成树,然后如果插入一条非树边,那么两个端点之间的边就都是在环中的边了. 用树剖维护就可以了. 时间复杂度 \(O(q\

luogu2542 航线规划 (树链剖分)

不会lct,所以只能树剖乱搞 一般这种删边的题都是离线倒着做,变成加边 他要求的结果其实就是缩点以后两点间的距离. 然后先根据最后剩下的边随便做出一个生成树,然后假装把剩下的边当成加边操作以后处理 这样的话,就可以做树剖来维护现在的两点间距离. 然后考虑加边,其实就是加了一条边然后某一处成环了,缩成了一个点. 这样的话,就可以把这条边两个端点间的距离都改成0,假装缩了点. 最后再倒着输出答案就行了. 1 #include<cstdio> 2 #include<cstring> 3

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

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航

[BZOJ2402]陶陶的难题II(树链剖分+线段树维护凸包+分数规划)

陶陶的难题II 时间限制:40s      空间限制:128MB 题目描述 输入格式 第一行包含一个正整数N,表示树中结点的个数. 第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5). 第三行包含N个正实数,第i个数表示yi (1<=yi<=10^5). 第四行包含N个正实数,第i个数表示pi (1<=pi<=10^5). 第五行包含N个正实数,第i个数表示qi (1<=qi<=10^5). 下面有N-1行,每行包含两个正整数a,b(1<

【模板时间】◆模板&#183;II◆ 树链剖分

[模板·II]树链剖分 学长给我讲树链剖分,然而我并没有听懂,还是自学有用--另外感谢一篇Blog +by 自为风月马前卒+ 一.算法简述 树链剖分可以将一棵普通的多叉树转为线段树计算,不但可以实现对一棵子树的操作,还可以实现对两点之间路径的操作,或是求 LCA(看起来很高级). 其实树链剖分不算什么特别高难的算法,它建立在 LCA.线段树.DFS序 的基础上(如果不了解这些算法的还是先把这些算法学懂再看树链剖分吧 QwQ).又因为树链剖分的基础算法不难,树链剖分的题也逐渐被引入 OI 赛中.

【树链剖分】【分类讨论】水果姐逛水果街Ⅲ

3306 水果姐逛水果街Ⅲ 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 大师 Master 题目描述 Description 连续两天都没有被cgh难倒,水果姐心情很不错,第三天又来逛水果街. 今天cgh早早就来到了水果街等水果姐,因为他带来了帮手cys.cgh的魔法是把水果街变成树结构,而cys的魔法是瞬间改变某家店的水果价格.一边问一边改,绝不给水果姐思考的时间! 同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. cgh和cys