首页 > 代码库 > cogs2557 天天爱跑步 LCA
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 天天爱跑步 LCA