• cogs2557 天天爱跑步 LCA


    从去年$11$月填到现在的超级天坑……链接:http://cogs.pro/cogs/problem/problem.php?pid=2557

    题意……给出一棵树,上面有一堆链,求出每个节点在指定的时刻有几条链恰好到达……

    联赛超纲的开始……

    详细叙述一下从去年十一月到现在的心路历程……

    $2016.11$现场:卧槽这题一脸不可做啊……

    $2016.12$:这个题出错地方了吧……

    $2017.1$:什么玩意……好像是图上的吧……

    $2017.2$(此时刚刚学习树):我好像会点了……(会什么?)如何建树……

    $2017.3$:……前$25$分好像可做了?……

    $2017.4$:卧槽我真是思博,链的数据都看不出来……

    $2017.5$(学了树剖):这个东西树剖可做?……

    $2017.6$:树剖确实可做……但是……一联赛不考,二修改些什么呢……

    $2017.7$(听$ysf$讲树上差分):大概知道怎么修改了……待我推一推式子……

    $2017.8$:噫!好!我过了!

    不扯了好好写题解……

    首先,每个人跑的路径$S->T$可以被拆分为两段:一段是从$S$到$LCA(S,T)$的向上阶段,另一段是从$LCA(S,T)$到$T$的向下阶段。接下来,我们分开进行考虑。

    首先我们考虑向上阶段。一个人被某个点观察员看到,必要条件是他经过那个点(废话),充要条件是$deep[S]-time[i]=deep[i]$,其中,$time[i]$是该观察员观察的时间。

    所以这个玩家一定是在这个点的子树之中(废话),那么我们搞一个$dfs$序,这个东西就被打成了区间问题。

    接下来的问题就变成了:如何查询这个区间内出现了多少人。

    这个解决方法可以说清奇古怪:每一层建一棵线段树(人傻自带一个$log$)。似乎看到了内存炸飞的景象?所以我们丢掉这些,动态开点……那么问题就变成了在$deep[i]+time[i]$所在这个子树上从进入这棵树到出这棵树有几个人的问题。

    但是一个更大的难点又来了,怎么修改数目……

    这就是我$7$月份才有了些许思路的原因了:听了$ysf$讲了树上差分(%%%$ysf$),意识到这条路径上全部增加可以差分为该点$+1$s,终点的下一个节点$-1$s。然后我们就直接在深度为$deep[S]$的线段树上操作、查询就可以了。

    向下路径同理,只不过式子变成了$deep[S]-2*deep[LCA(S,T)]=time[i]-deep[i]$。由于等号左边可能为负,所以我们直接右移$2*n$位进行查询。也正因为如此,向上修改完成之后需要立刻查询,然后重建线段树,否则会发生混淆。

    代码拿去吧……真的是乱七八糟……(话说最后我也没有用树剖诶……)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 const int maxn=300005;
      7 struct node
      8 {
      9     int from,to,next;
     10 }edge[maxn<<1];
     11 int head[maxn],tot;
     12 void addedge(int u,int v)
     13 {
     14     edge[++tot]=(node){u,v,head[u]};head[u]=tot;
     15 }
     16 int n,tim[maxn],dep[maxn],rt[maxn][20],m,dfn[maxn],cnt,las[maxn];
     17 void dfs(int root,int pa,int depth)
     18 {
     19     dfn[root]=++cnt;rt[root][0]=pa;dep[root]=depth;
     20     for(int i=head[root];i;i=edge[i].next)
     21     {
     22         int v=edge[i].to;
     23         if(rt[root][0]!=v)dfs(v,root,depth+1);
     24     }
     25     las[root]=cnt;
     26 }
     27 void init()
     28 {
     29     for(int i=1;(1<<i)<=n;i++)
     30         for(int j=1;j<=n;j++)rt[j][i]=-1;
     31     for(int j=1;(1<<j)<=n;j++)
     32         for(int i=1;i<=n;i++)
     33             if(rt[i][j-1]!=-1)rt[i][j]=rt[rt[i][j-1]][j-1];
     34 }
     35 int lca(int x,int y)
     36 {
     37     int i;
     38     if(dep[x]<dep[y])swap(x,y);
     39     for(i=0;(1<<i)<=dep[x];i++);i--;
     40     for(int j=i;j>=0;j--)
     41         if(dep[x]-(1<<j)>=dep[y])x=rt[x][j];
     42     if(x==y)return y;
     43     for(int j=i;j>=0;j--)
     44         if(rt[x][j]!=-1&&rt[x][j]!=rt[y][j])x=rt[x][j],y=rt[y][j];
     45     return rt[x][0];
     46 }
     47 struct chara
     48 {
     49     int source,target,lca;
     50 }people[maxn];
     51 int sm[7500005],root[maxn<<2],lc[7500005],rc[7500005],num;
     52 #define mid ((l+r)>>1)
     53 #define lson lc[now],l,mid
     54 #define rson rc[now],mid+1,r
     55 void clear()
     56 {
     57     memset(sm,0,sizeof(sm));memset(root,0,sizeof(root));
     58     memset(lc,0,sizeof(lc));memset(rc,0,sizeof(rc));num=0;
     59 }
     60 void update(int &now,int l,int r,int pos,int val)
     61 {
     62     if(!pos)return;
     63     if(!now)now=++num;
     64     sm[now]+=val;
     65     if(l==r)return;
     66     if(pos<=mid)update(lson,pos,val);
     67     else update(rson,pos,val);
     68 }
     69 int ans[maxn];
     70 int query(int &now,int l,int r,int L,int R)
     71 {
     72     if(!now)return 0;
     73     if(L<=l&&r<=R)return sm[now];
     74     if(R<=mid)return query(lson,L,R);
     75     else if(L>mid)return query(rson,L,R);
     76     else return query(lson,L,mid)+query(rson,mid+1,R);
     77 }
     78 int haha()
     79 {
     80     freopen("runninga.in","r",stdin);
     81     freopen("runninga.out","w",stdout);
     82     scanf("%d%d",&n,&m);
     83     for(int i=1;i<n;i++)
     84     {
     85         int x,y;scanf("%d%d",&x,&y);
     86         addedge(x,y);addedge(y,x);
     87     }
     88     dfs(1,-1,1);init();
     89     for(int i=1;i<=n;i++)scanf("%d",&tim[i]);
     90     for(int i=1;i<=m;i++)
     91     {
     92         scanf("%d%d",&people[i].source,&people[i].target);
     93         people[i].lca=lca(people[i].source,people[i].target);
     94     }
     95     for(int i=1;i<=m;i++)
     96     {
     97         int deep=dep[people[i].source];
     98         update(root[deep],1,n,dfn[people[i].source],1);
     99         update(root[deep],1,n,dfn[rt[people[i].lca][0]],-1);
    100     }
    101     for(int i=1;i<=n;i++)ans[i]+=query(root[dep[i]+tim[i]],1,n,dfn[i],las[i]);
    102     clear();
    103     for(int i=1;i<=m;i++)
    104     {
    105         int deep=dep[people[i].source]-(dep[people[i].lca]<<1)+(n<<1);
    106         update(root[deep],1,n,dfn[people[i].target],1);
    107         update(root[deep],1,n,dfn[people[i].lca],-1);
    108     }
    109     for(int i=1;i<=n;i++)ans[i]+=query(root[tim[i]-dep[i]+(n<<1)],1,n,dfn[i],las[i]);
    110     for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    111 }
    112 int sb=haha();
    113 int main(){;}
    cogs2557
  • 相关阅读:
    windows的80端口被占用时的处理方法
    Ansible自动化运维工具安装与使用实例
    Tomcat的测试网页换成自己项目首页
    LeetCode 219. Contains Duplicate II
    LeetCode Contest 177
    LeetCode 217. Contains Duplicate
    LeetCode 216. Combination Sum III(DFS)
    LeetCode 215. Kth Largest Element in an Array(排序)
    Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)
    Contest 176
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7355841.html
Copyright © 2020-2023  润新知