zoukankan      html  css  js  c++  java
  • 洛谷P1600 天天爱跑步

    传送门

    将每个玩家的路径看作两部分:向根上行以及向叶子下行

    p为每个点出现观察员的时间。子树中的起点u到当前点v的路径即是上行,如果dep[v]+p[v]=dep[u],则u对v产生一个贡献。当前点u到子树中终点v的路径即是下行,如果dep[v]-dis(x,v)=dep[u]-p[u](x为这条路径的起点,v为终点,dis(x,v)为两点的距离),则v对u产生一个贡献。

    树上差分,将所有路径标记到树上。开两个桶分别存所有起点的dep[x]和所有终点的dep[x]-dis,在起点和终点处使贡献+1,在lca处把它们的贡献分别-1,表示出了这棵子树以后不再产生贡献。统计答案的时候,如果一条路径对lca产生了贡献,那么起点和终点都会算一次,因此lca处将贡献-1的时候要判断是否被这条路径贡献了答案。

    查询某棵子树中点的答案的时候,有可能其它子树的贡献仍然留在桶内。由于这道题只是记录贡献的累计,因此在dfs到达某个点的时候记录一次答案,将要出这个点的时候再查询一次答案,减去第一次记录的值使差值成为最终答案。

    统计某个点的答案时,先把所有+1的贡献扔进桶里,进行查询,再处理所有贡献-1的操作。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    const int N=300010,M=300010;
    int n,m,a[N];
    int ver[2*N],Next[2*N],head[N],tot;
    int dep[N],ans[2][N];
    int c[2][600010];
    struct node{
        int opt,val,x,dis;
        node(int a=0,int b=0,int c=0,int d=0){
            opt=a,val=b,x=c,dis=d;
        }
    };
    vector<node>s[N];
    void add(int x,int y){
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    int st[N][21];
    void dfs(int x,int fa){
        for(int i=1;i<=20;i++){
            st[x][i]=st[st[x][i-1]][i-1];
            if(!st[x][i])break;
        }
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            dep[y]=dep[x]+1;
            st[y][0]=x;
            dfs(y,x); 
        }
    }
    int get(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        for(int i=20;i>=0;i--){
            if(st[x][i]&&dep[st[x][i]]>=dep[y])x=st[x][i];
        }
        if(x==y)return x;
        for(int i=20;i>=0;i--){
            if(st[x][i]!=st[y][i]){
                x=st[x][i],y=st[y][i];
            }
        }
        return st[x][0];
    }
    void dfs1(int x,int fa){
        ans[0][x]=c[0][dep[x]+a[x]];
        ans[1][x]=c[1][dep[x]-a[x]+N];
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            dfs1(y,x);
        }
        for(int i=0;i<s[x].size();i++){
            int v=s[x][i].x,val=s[x][i].val,opt=s[x][i].opt,dis=s[x][i].dis;
            if(val==-1)continue;
            if(opt==0){
                c[0][dep[v]]+=val;
            }
            else{
                c[1][dep[v]-dis+N]+=val;
            }
        }
        ans[0][x]=c[0][dep[x]+a[x]]-ans[0][x];
        ans[1][x]=c[1][dep[x]-a[x]+N]-ans[1][x];
        for(int i=0;i<s[x].size();i++){
            int v=s[x][i].x,val=s[x][i].val,opt=s[x][i].opt,dis=s[x][i].dis;
            if(val==1)continue;
            if(opt==0){
                c[0][dep[v]]+=val;
                if(dep[x]+a[x]==dep[v])ans[0][x]--;
            }
            else{
                c[1][dep[v]-dis+N]+=val;
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        dfs(1,0);
        for(int i=1,x,y;i<=m;i++){
            scanf("%d%d",&x,&y);
            int lca=get(x,y);
            int dis=dep[x]+dep[y]-2*dep[lca];
            s[x].push_back(node(0,1,x,0));
            s[y].push_back(node(1,1,y,dis));
            s[lca].push_back(node(0,-1,x,0));
            s[lca].push_back(node(1,-1,y,dis));
        }
        dfs1(1,0);
        for(int i=1;i<=n;i++){
            printf("%d ",ans[0][i]+ans[1][i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    电力项目七--js控制文字内容过长的显示和文本字数的显示
    电力项目六--运行监控设计
    Maven开发系统
    SSH电力项目一 搭建Hibernate框架
    网站添加用户风险测评
    tomcat中文配置
    Tomcat映射路径的配置方法
    java中计算时间差
    NSTimer+倒计时功能实现
    设置UITextView光标从起始位置开始
  • 原文地址:https://www.cnblogs.com/chloris/p/11861140.html
Copyright © 2011-2022 走看看