zoukankan      html  css  js  c++  java
  • 洛谷$P1600$ 天天爱跑步 树上差分

    正解:树上差分

    解题报告:

    传送门$QwQ$!

    这题还挺妙的,,,我想了半天才会$kk$

    首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只港$S-LCA$的做法了$QwQ$

    考虑对于一个观察点$j$,若要观察到玩家$i$,则有$dep_j+w_j=dep_i$.发现现在就只用统计$j$的子树内所有起点深度等于$dep_j+w_j$的就行.

    显然考虑树上差分呗.就开个桶记$dep_i$,对每条路径在$S$处给$dep_S$+1,到$LCA$处给$dep_S-1$,然后在每个观察点答案就直接查$t_{dep_j+w_j}$就完事$QwQ$.

    然后$LCA-T$差不多?就表达式变下,细节注意下,$over$

    嗷然后其实这里$LCA$是算重了的嘛,最后把重复的贡献减去就好$QwQ$

     

    #include<bits/stdc++.h>
    using namespace std;
    #define il inline
    #define gc getchar()
    #define t(i) edge[i].to
    #define w(i) edge[i].wei
    #define fy(i) edge[i].fy
    #define ri register int
    #define rb register bool
    #define rc register char
    #define rp(i,x,y) for(ri i=x;i<=y;++i)
    #define my(i,x,y) for(ri i=x;i>=y;--i)
    #define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)
    
    const int N=600000+10;
    int ed_cnt,head[N],n,m,fa[N][20],w[N],dep[N],mx,tz[N<<1],as[N],val[N];
    struct ed{int to,nxt,wei,fy;}edge[N<<1];
    struct node{int fr,to,lca,len;}nod[N];
    vector<int>V1[N],V2[N],V3[N];
    
    il int read()
    {
        rc ch=gc;ri x=0;rb y=1;
        while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
        if(ch=='-')ch=gc,y=0;
        while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
        return y?x:-x;
    }
    il void ad(ri x,ri y){edge[++ed_cnt]=(ed){x,head[y]};head[y]=ed_cnt;}
    void dfs(ri x){e(i,x)if(!dep[t(i)])dep[t(i)]=dep[x]+1,fa[t(i)][0]=x,dfs(t(i));}
    il int lca(ri x,ri y)
    {
        if(dep[x]<dep[y])swap(x,y);my(i,19,0)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];if(x==y)return x;
        my(i,19,0)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];;return fa[x][0];
    }
    void dfs1(ri x)
    {
        ri tmp=w[x]+dep[x],t;if(tmp<=mx)t=tz[tmp];e(i,x)if(t(i)!=fa[x][0])dfs1(t(i));
        tz[dep[x]]+=val[x];if(tmp<=mx)as[x]=tz[tmp]-t;ri sz=V1[x].size();rp(i,0,sz-1)--tz[dep[V1[x][i]]];
    }
    void dfs2(ri x)
    {
        ri tmp=dep[x]-w[x]+N,t=tz[tmp];e(i,x)if(t(i)!=fa[x][0])dfs2(t(i));
        ri sz=V2[x].size();rp(i,0,sz-1)++tz[V2[x][i]];as[x]+=tz[tmp]-t;sz=V3[x].size();rp(i,0,sz-1)--tz[V3[x][i]];
    }
    il void pre()
    {
        n=read();m=read();rp(i,1,n-1){ri x=read(),y=read();ad(x,y);ad(y,x);ad(x,y);}rp(i,1,n)w[i]=read();
        dep[1]=1;dfs(1);rp(i,1,19)rp(j,1,n)fa[j][i]=fa[fa[j][i-1]][i-1];rp(i,1,n)mx=max(mx,dep[i]);
    }
    il void work()
    {
        rp(i,1,m)
        {
            ri x=read(),y=read(),lcaa=lca(x,y);nod[i]=(node){x,y,lcaa,dep[x]+dep[y]-(dep[lcaa]<<1)};
            V1[lcaa].push_back(x);++val[x];
        }
        dfs1(1);
        rp(i,1,m){ri tmp=dep[nod[i].to]-nod[i].len+N;V2[nod[i].to].push_back(tmp),V3[nod[i].lca].push_back(tmp);}
        memset(tz,0,sizeof(tz));dfs2(1);
        rp(i,1,m)if(dep[nod[i].fr]-dep[nod[i].lca]==w[nod[i].lca])--as[nod[i].lca];rp(i,1,n)printf("%d ",as[i]);
    }
    
    int main()
    {
        freopen("1600.in","r",stdin);freopen("1600.out","w",stdout);
        pre();work();
        return 0;
    }
    出于一些不知名原因我要把数组开大一倍不然会$WA$第13个点$kk$

     

  • 相关阅读:
    hdu 4115 石头剪子布(2-sat问题)
    AFNetWorking POST Multi-Part Request 上传图片
    左右c++与java中国的垃圾问题的分析与解决
    ACM核武器
    MAX2323E
    cocos2d-x 发动机分析:程序如何开始和结束?
    STL 源代码分析 算法 stl_heap.h
    Android 4.4(KitKat)表格管理子系统
    Swift
    Swift
  • 原文地址:https://www.cnblogs.com/lqsukida/p/11428923.html
Copyright © 2011-2022 走看看