zoukankan      html  css  js  c++  java
  • 【NOIP2016】【LCA】【树上差分】【史诗级难度】天天爱跑步

    学弟不是说要出丧题吗》》所以我就研究了1天lca又研究了1天tj然后研究了一天天天爱跑步,终于写了出来。(最后的平均用时为240ms。。。比学弟快了1倍。。。)

    题意:给你颗树,然后有m个东西在树上移动,每s移动一条边。路径为S[i]->T[i],现在求在w[i]时第i各节点上有多少个东西。

    解题思路:首先,我们考虑使用lca将走过的路径拆成2半,一段为S->f(lca),一段为f(lca)->T,显然对于一个点在T时所经过他的东西数,我们是可以通过树上差分求出的,具体方法:首先讲一下从S->f的做法,考虑按深度差分,显然第i个人第0s的位置为deep[S],于是记此时差分数组中deep[S]--,这样若一个人在w[i]时经过点i,显然我们可以认为差分数组中的[deep[i]-w[i]]就可以代表了这个点的答案,但显然这是过于理想化的考虑,显然对于一个节点,其子树外的情况也会影响到这个点的数值,因而我们需要在遍历以这个节点为根的子树前先减去差分数组的值,这样就可以使得答案一定是子树内的情况了。从f->T也同样如此可以完成,这里不再赘述,具体实现请参考AC代码,注意一些细节的处理:).

    AC代码:

     1 #include<stdio.h>
     2 #define MN 300005
     3 #define nt edge[i].to
     4 struct zxy{int to,next;}edge[MN*8];//链表(把多个链表都塞进去了)
     5 int cnt,h[MN],q[MN],adh1[MN],deh1[MN],adh2[MN],deh2[MN];//各链表表头
     6 int qans[MN],tim[MN],deep[MN],n,m,chafen[MN*3],fa[MN],ans[MN],x[MN],y[MN];
     7 bool vis[MN];
     8 inline void ins(int *h,int x,int y){edge[++cnt].next=h[x],edge[cnt].to=y,h[x]=cnt;}//构造链表
     9 inline int getfa(int x){return fa[x]?fa[x]=getfa(fa[x]):x;}//并查集
    10 inline int in(){
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    13     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    14     return x*f;
    15 }
    16 inline void tjlca(int x,int d){
    17     deep[x]=d;vis[x]=1;
    18     for (register int i=h[x]; i; i=edge[i].next) 
    19         if (!vis[nt])tjlca(nt,d+1),fa[nt]=x;
    20     for (register int i=q[x]; i; i=edge[i].next)
    21         if (qans[nt]) qans[nt]=getfa(qans[nt]);
    22         else qans[nt]=x;
    23 }//tarjan算法求LCA
    24 inline void dfs1(int u){
    25     vis[u]=0;ans[u]-=chafen[deep[u]-tim[u]];
    26     for (register int i=h[u]; i; i=edge[i].next) if (vis[nt]) dfs1(nt);
    27     for (register int i=adh1[u]; i; i=edge[i].next) ++chafen[nt];
    28     ans[u]+=chafen[deep[u]-tim[u]];
    29     for (register int i=deh1[u]; i; i=edge[i].next) --chafen[nt];
    30 }//dfs处理S->f的
    31 inline void dfs2(int u){
    32     vis[u]=1;ans[u]-=chafen[deep[u]+tim[u]];
    33     for (register int i=h[u]; i; i=edge[i].next) if (!vis[nt]) dfs2(nt);
    34     for (register int i=adh2[u]; i; i=edge[i].next) ++chafen[nt];
    35     ans[u]+=chafen[deep[u]+tim[u]];
    36     for (register int i=deh2[u]; i; i=edge[i].next) --chafen[nt];
    37 }//dfs处理f->T的
    38 void read(){
    39     n=in(),m=in();int u,v;
    40     for (int i=1; i<n; ++i) u=in(),v=in(),ins(h,u,v),ins(h,v,u);
    41     for (register int i=1; i<=n; ++i) tim[i]=in()-MN;//为了防止减法出现负数,所以我们要这么做。
    42     for (register int i=1; i<=m; ++i) x[i]=in(),y[i]=in(),ins(q,x[i],i),ins(q,y[i],i);
    43 }//输入
    44 void init(){
    45     tjlca(1,0);
    46     for (register int i=1; i<=m; ++i){
    47         int f=qans[i],u=x[i],v=y[i];
    48         if (f==v) ins(adh2,u,deep[u]+MN),ins(deh2,v,deep[u]+MN);
    49         else{
    50             if (f==u) ins(adh1,v,deep[u]+MN),ins(deh1,u,deep[u]+MN);
    51             else{
    52                 ins(adh2,u,deep[u]+MN);
    53                 ins(deh2,f,deep[u]+MN);
    54                 ins(adh1,v,(deep[f]<<1)-deep[u]+MN);
    55                 ins(deh1,f,(deep[f]<<1)-deep[u]+MN);
    56                 if(deep[f]==deep[u]-tim[f]-MN) --ans[f];        
    57             }
    58         }
    59     }
    60 }//处理差分位置
    61 void solve(){
    62     dfs1(1);//进行第一次遍历统计答案
    63     for (register int i=1; i<=n; ++i) tim[i]+=MN<<1;//这个处理很关键!
    64     dfs2(1);
    65     for (register int i=1; i<n; ++i) printf("%d ",ans[i]); printf("%d",ans[n]);
    66 }
    67 int main(){
    68     read();
    69     init();
    70     solve();
    71 }
  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/Melacau/p/NOIP2016_running.html
Copyright © 2011-2022 走看看