zoukankan      html  css  js  c++  java
  • [NOIp2016提高组]天天爱跑步

    题目大意:
      有一棵n个点的树,每个点上有一个摄像头会在第w[i]秒拍照。
      有m个人再树上跑,第i个人沿着s[i]到t[i]的路径跑,每秒钟跑一条边。
      跑到t[i]的下一秒,人就会消失。
      问每个摄像头会拍下几个人。

    思路:
      首先很显然是要求LCA的。
      求完LCA怎么办?
      我们可以用树上差分的方法分别维护向上、向下的链。
      每一条路径,我们可以在s,t,lca,par[lca]上分别打标记。
      s +dep[s]
      t +dep[t]-len
      lca -dep[s]
      par[lca] +len-dep[t]
      其中有一些是向上走的链、有一些是向下走的链,因此我们还需要将它们区分开来。
      一个点x满足条件当且仅当x在s到lca的路上且dep[x]-dep[s]=w[x],
      或者x在lca到t的路上且dep[lca]-dep[s]+deo[lca]-dep[x]=w[x]。
      最后从根节点DFS统计一下,访问到x结点就把对应的标记加进去,ans[x]=统计完子树后的答案-统计之前的答案。
      另外注意dep[t]-len可能会是负的,因此我们可以将它们整体往右移一些位置。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 inline int getint() {
     5     register char ch;
     6     while(!isdigit(ch=getchar()));
     7     register int x=ch^'0';
     8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     9     return x;
    10 }
    11 const int N=299999,logN=19;
    12 std::vector<int> e[N];
    13 inline void add_edge(const int &u,const int &v) {
    14     e[u].push_back(v);
    15     e[v].push_back(u);
    16 }
    17 int w[N],dep[N],anc[N][logN];
    18 inline int log2(const float &x) {
    19     return ((unsigned&)x>>23&255)-127;
    20 }
    21 void dfs(const int &x,const int &par) {
    22     dep[x]=dep[par]+1;
    23     anc[x][0]=par;
    24     for(register int i=1;i<=log2(dep[x]);i++) {
    25         anc[x][i]=anc[anc[x][i-1]][i-1];
    26     }
    27     for(register unsigned i=0;i<e[x].size();i++) {
    28         const int &y=e[x][i];
    29         if(y==par) continue;
    30         dfs(y,x);
    31     }
    32 }
    33 inline int lca(int x,int y) {
    34     if(dep[x]<dep[y]) std::swap(x,y);
    35     for(register int i=log2(dep[x]-dep[y]);i>=0;i--) {
    36         if(dep[anc[x][i]]>=dep[y]) {
    37             x=anc[x][i];
    38         }
    39     }
    40     if(x==y) return x;
    41     for(register int i=log2(dep[x]);i>=0;i--) {
    42         if(anc[x][i]!=anc[y][i]) {
    43             x=anc[x][i];
    44             y=anc[y][i];
    45         }
    46     }
    47     return anc[x][0];
    48 }
    49 struct Tag {
    50     bool type;
    51     int val,sgn;
    52 };
    53 std::vector<Tag> tag[N];
    54 int ans[N];
    55 int cnt1[N<<2],cnt2[N<<2];
    56 void stat(const int &x) {
    57     const int tmp=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<1)];
    58     for(register unsigned i=0;i<tag[x].size();i++) {
    59         const Tag &t=tag[x][i];
    60         (t.type?cnt1:cnt2)[t.val]+=t.sgn;
    61     }
    62     for(unsigned i=0;i<e[x].size();i++) {
    63         const int &y=e[x][i];
    64         if(y==anc[x][0]) continue;
    65         stat(y);
    66     }
    67     ans[x]=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<1)]-tmp;
    68 }
    69 int main() {
    70     const int n=getint(),m=getint();
    71     for(register int i=1;i<n;i++) {
    72         add_edge(getint(),getint());
    73     }
    74     for(register int i=1;i<=n;i++) {
    75         w[i]=getint();
    76     }
    77     dfs(1,0);
    78     for(register int i=0;i<m;i++) {
    79         const int s=getint(),t=getint(),p=lca(s,t),len=dep[s]+dep[t]-(dep[p]<<1);
    80         tag[s].push_back((Tag){1,dep[s],1});
    81         tag[t].push_back((Tag){0,dep[t]-len+(N<<1),1});
    82         tag[p].push_back((Tag){1,dep[s],-1});
    83         tag[anc[p][0]].push_back((Tag){0,dep[t]-len+(N<<1),-1});
    84     }
    85     stat(1);
    86     for(register int i=1;i<n;i++) {
    87         printf("%d ",ans[i]);
    88     }
    89     printf("%d",ans[n]);
    90     return 0;
    91 }
  • 相关阅读:
    ios 如何获得系统时间和日期
    IOS开发使用委托delegate在不同窗口之间传递数据
    集合视图UICollectionView 介绍及其示例程序
    iOS6新特征:UICollectionView介绍
    ios delegate和protocol
    iOS页面跳转及数据传递
    [转载]iOS6新特征:UICollectionView官方使用示例代码研究
    跟上潮流:十大移动应用开发平台
    UITextField 如何设置为密码方式显示?
    【转】 Android中Intent组件详解
  • 原文地址:https://www.cnblogs.com/skylee03/p/7784550.html
Copyright © 2011-2022 走看看