zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    JS中字符串的true转化为boolean类型的true
    jquery select change下拉框选项变化判断选中值
    C# 使用 NPOI 库读写 Excel 文件
    通过微信分享链接,后面被加上from=singlemessage&isappinstalled=1导致网页打不开
    C# 中使用 ThoughtWorks.QRCode.dll 生成指定尺寸和边框宽度的二维码
    除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效
    SQL查询语句如何能够让指定的记录排在最后
    搞懂 JavaScript 继承原理
    基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
    SqlServer 使用sys.dm_tran_locks处理死锁问题
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7355841.html
Copyright © 2011-2022 走看看