zoukankan      html  css  js  c++  java
  • [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
    ",q[i].ans);
    } 
    View Code
  • 相关阅读:
    Salesforce和SAP Netweaver里数据库表的元数据设计
    Salesforce平台支持多租户Multi tenant的核心设计思路
    S/4HANA生产订单增强WORKORDER_UPDATE方法BEFORE_UPDATE参数分析
    S/4HANA生产订单的标准状态和透明工厂原型状态的映射
    1048. Find Coins (25)
    1101. Quick Sort (25)
    1009. Product of Polynomials (25)
    pta 奇数值结点链表&&单链表结点删除
    1007. Maximum Subsequence Sum (25)
    1006. Sign In and Sign Out (25)
  • 原文地址:https://www.cnblogs.com/yyys-/p/11335769.html
Copyright © 2011-2022 走看看