zoukankan      html  css  js  c++  java
  • NOIP2016天天爱跑步

    NOIP2016天天爱跑步

    这题一看显然lca+树上差分,但是因为有w的限制不能直接加,所以考虑权值线段树合并,

    每个选手的起点终点对于不同的节点的影响是不同的,这就非常麻烦了,但是可以发现无论如何他的深度是固定的,而对于一个节点i,能使他+1有如下两种情况:

    1.dep[x]=dep[i]-w[i]

    2.dep[x]=dep[i]+w[i]

    于是对于一组s,t,求出他们的lca将路径分为两段,给s的dep[s]值加1,fa[lca]减1,t的2*dep[lca]-dep[s]加1,lca减1,

    最后dfs线段树合并,对于一个节点x,查询对应线段树中dep[x]-w[x]+dep[x]+w[x]的个数,注意如果w[x]是0要除2(因为多加了一遍)。

    有了“雨天的尾巴”的经验,这道题代码还是很好调的。

     

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    struct edge
    {
        int u,v,nxt;
        #define u(x) ed[x].u
        #define v(x) ed[x].v
        #define n(x) ed[x].nxt
    }ed[300010];
    int first[300010],num_e;
    #define f(x) first[x]
    int n,m,root;
    int dep[300010],du[300010];
    struct tree
    {
        int ls,rs,l,r,sum;
        #define ls(x)  tr[x].ls
        #define rs(x)  tr[x].rs
        #define l(x)   tr[x].l
        #define r(x)   tr[x].r
        #define sum(x) tr[x].sum 
    }tr[10000010];
    int cnt,T[300010];
    void add(int &x,int y,int z,int l,int r)
    {     
        if(!x){x=++cnt;l(x)=l,r(x)=r;}
        if(l==r){sum(x)+=z;return;}
        int mid=(l(x)+r(x))>>1;
        if(y<=mid)add(ls(x),y,z,l,mid);
        else      add(rs(x),y,z,mid+1,r);
        sum(x)=0;
        if(ls(x))sum(x)+=sum(ls(x));
        if(rs(x))sum(x)+=sum(rs(x));
    }
    int merge(int x,int y,int l,int r)
    {
        if(!x||!y)return x+y;
        if(l==r){sum(x)+=sum(y);return x;}
        int mid=(l+r)>>1;
        ls(x)=merge(ls(x),ls(y),l,mid);
        rs(x)=merge(rs(x),rs(y),mid+1,r);
        sum(x)=sum(ls(x))+sum(rs(x));
        return x;
    }
    int ask(int x,int val,int l,int r)
    {
        if(l==r){return sum(x);}
        int mid=(l+r)>>1;
        if(val<=mid)return ask(ls(x),val,l,mid);
        else        return ask(rs(x),val,mid+1,r);
    }
    int f[300010][21];
    int LCA(int x,int y)
    {
        if(x==y)return x;
        if(dep[x]>dep[y])swap(x,y);
        while(dep[x]<dep[y])
            for(int i=0;;i++)
            if(dep[f[y][i]]<dep[x])
            {y=f[y][i-1];break;}
        if(x==y)return x;
        while(f[x][0]!=f[y][0])
            for(int i=0;;i++)
            if(f[x][i]==f[y][i])
            {x=f[x][i-1],y=f[y][i-1];break;}
        return f[x][0];
    }
    void dfs(int x,int de,int fa)
    {
        dep[x]=de;f[x][0]=fa;
        for(int i=f(x);i;i=n(i))
            dfs(v(i),de+1,x);
    }
    int ans[300010],w[300010];
    void dfs2(int x)
    {
        for(int i=f(x);i;i=n(i))
        {
            dfs2(v(i));
            T[x]=merge(T[x],T[v(i)],-n-1,n+1);
        }
        int t1=ask(T[x],dep[x]+w[x],-n-1,n+1),t2=ask(T[x],dep[x]-w[x],-n-1,n+1);
        ans[x]=t1+t2;
        if(!w[x])ans[x]-=t1;
    }
    inline void add_e(int u,int v);
    signed main()
    {
    //    freopen("in.txt","r",stdin);
    
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add_e(u,v);du[v]++;
        }
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<=n;i++)
        if(!du[i]){root=i;break;}
        dfs(root,1,0);
        for(int i=1;i<=20;i++)
            for(int j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1];
        int s,t;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&s,&t);
            int lca=LCA(s,t);
            add(T[s],dep[s],1,-n-1,n+1);
            if(lca!=root){add(T[f[lca][0]],dep[s],-1,-n-1,n+1);}
            add(T[t],2*dep[lca]-dep[s],1,-n-1,n+1);
            add(T[lca],2*dep[lca]-dep[s],-1,-n-1,n+1);
        }
        dfs2(root);
        printf("%d",ans[1]);
        for(int i=2;i<=n;i++)
        printf(" %d",ans[i]);
    }
    inline void add_e(int u,int v)
    {
        ++num_e;
        u(num_e)=u;
        v(num_e)=v;
        n(num_e)=f(u);
        f(u)=num_e;
    }
    View Code

     

     

  • 相关阅读:
    join_tab计算代价
    outer join test
    突然觉得mysql优化器蛮简单
    将数据库字段从float修改为decimal
    小米初体验
    简述安装android开发环境
    Rust语言:安全地并发
    awk里的各种坑
    ubuntu下使用C语言开发一个cgi程序
    Ubuntu下安装和配置Apache2
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11179295.html
Copyright © 2011-2022 走看看