题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。天天爱跑步是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。
现在有个玩家,第个玩家的 起点为Si ,终点为Ti 。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以 每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选 择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也正好到达了结点J 。 小C想知道 每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时 间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察 到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。
输入格式
第一行有两个整数N和M 。其中N代表树的结点数量, 同时也是观察员的数量, M代表玩家的数量。
接下来n-1 行每行两个整数U和V ,表示结点U 到结点V 有一条边。
接下来一行N 个整数,其中第个整数为Wj , 表示结点出现观察员的时间。
接下来 M行,每行两个整数Si和Ti,表示一个玩家的起点和终点。
对于所有的数据,保证 。1<=Si,Ti<=N,0<=Wj<=N
输出格式
输出1行N 个整数,第j个整数表示结点j的观察员可以观察到多少人。
解题思路:
方法一:线段树+树链剖分
首先,我们考虑什么样的玩家可以被看到,那么就是说什么时候玩家到某个节点。
设玩家初始时的位置深度为d。
大概是这样的,如果玩家在向上走时,会在0时刻走到路径上d深度的点,在1时刻走到d-1深度的点,2时刻走到d-2是深度的点。
那么在向上走的过程中,所经过点上的观察员只要使等式(w+deep)=d成立,就能看见玩家。
同样的在玩家向下走的时候也有类似的结论,就是只要玩家的(d-2*路径上lca的deep)=(w-deep)就能看见。
那么我们开线段树存就好了。
对于每个深度开两棵线段树分别记录向下走的和向上走的某个节点观察的值,也就是说在每一个玩家的d上的线段树对于每个玩家经历的点上统一+1。
也就是说树链上+1,这样只要单点查询就可以了。
树链上+1,使用树链剖分就好了^_^
线段树占很大空间动态开点就好了
还有对于一些深度较浅的点我们发现最终的向下行走的索引可能为负,所以对于向下走的线段树索引统一加上3e5
大概就是这样了^_^
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=(int)(3e5); 6 const int T=(int)(13000000); 7 struct pnt{ 8 int w; 9 int hd; 10 int dp; 11 int fa; 12 int wgt; 13 int mxs; 14 int ind; 15 int top; 16 }p[N]; 17 struct ent{ 18 int twd; 19 int lst; 20 }e[N*2]; 21 struct sgt{ 22 int ls; 23 int rs; 24 int vls; 25 }tr[T]; 26 int cnt; 27 int siz; 28 int dnt; 29 int n,m; 30 int rtu[N*2],rtd[N*2]; 31 int sta[N],fin[N]; 32 void ade(int f,int t) 33 { 34 cnt++; 35 e[cnt].twd=t; 36 e[cnt].lst=p[f].hd; 37 p[f].hd=cnt; 38 } 39 void Tr_pushdown(int spc) 40 { 41 if(tr[spc].ls) 42 tr[tr[spc].ls].vls+=tr[spc].vls; 43 if(tr[spc].rs) 44 tr[tr[spc].rs].vls+=tr[spc].vls; 45 tr[spc].vls=0; 46 } 47 void Tr_build(int &spc,int l,int r,int plc) 48 { 49 if(!spc) 50 spc=++siz; 51 if(l==r) 52 return ; 53 int mid=(l+r)/2; 54 if(plc<=mid) 55 Tr_build(tr[spc].ls,l,mid,plc); 56 else 57 Tr_build(tr[spc].rs,mid+1,r,plc); 58 } 59 60 void Tr_add(int ll,int rr,int l,int r,int spc,int v) 61 { 62 if(!spc) 63 return ; 64 if(ll>r||l>rr) 65 return ; 66 if(ll<=l&&rr>=r) 67 { 68 tr[spc].vls+=v; 69 return ; 70 } 71 int mid=(l+r)/2; 72 Tr_add(ll,rr,l,mid,tr[spc].ls,v); 73 Tr_add(ll,rr,mid+1,r,tr[spc].rs,v); 74 return ; 75 } 76 int Tr_val(int plc,int spc,int l,int r) 77 { 78 if(!spc) 79 return 0; 80 if(l==r) 81 return tr[spc].vls; 82 Tr_pushdown(spc); 83 int mid=(l+r)/2; 84 if(plc<=mid) 85 return Tr_val(plc,tr[spc].ls,l,mid); 86 else 87 return Tr_val(plc,tr[spc].rs,mid+1,r); 88 } 89 void Basic_dfs(int x,int f) 90 { 91 p[x].fa=f; 92 p[x].dp=p[f].dp+1; 93 p[x].wgt=1; 94 int maxs=0; 95 for(int i=p[x].hd;i;i=e[i].lst) 96 { 97 int to=e[i].twd; 98 if(to==f) 99 continue; 100 Basic_dfs(to,x); 101 p[x].wgt+=p[to].wgt; 102 if(maxs<p[to].wgt) 103 { 104 maxs=p[to].wgt; 105 p[x].mxs=to; 106 } 107 } 108 } 109 void Build_dfs(int x,int tp) 110 { 111 if(!x) 112 return ; 113 p[x].ind=++dnt; 114 p[x].top=tp; 115 Tr_build(rtu[p[x].dp+p[x].w],1,n,dnt); 116 Tr_build(rtd[p[x].w-p[x].dp+N],1,n,dnt); 117 Build_dfs(p[x].mxs,tp); 118 for(int i=p[x].hd;i;i=e[i].lst) 119 { 120 int to=e[i].twd; 121 if(p[to].ind) 122 continue; 123 Build_dfs(to,to); 124 } 125 } 126 int LCA(int x,int y) 127 { 128 while(p[x].top!=p[y].top) 129 { 130 if(p[p[x].top].dp<p[p[y].top].dp) 131 swap(x,y); 132 x=p[p[x].top].fa; 133 } 134 if(p[x].dp>p[y].dp) 135 swap(x,y); 136 return x; 137 } 138 int main() 139 { 140 scanf("%d%d",&n,&m); 141 for(int i=1;i<n;i++) 142 { 143 int x,y; 144 scanf("%d%d",&x,&y); 145 ade(x,y); 146 ade(y,x); 147 } 148 for(int i=1;i<=n;i++) 149 scanf("%d",&p[i].w); 150 for(int i=1;i<=m;i++) 151 scanf("%d%d",&sta[i],&fin[i]); 152 Basic_dfs(1,1); 153 Build_dfs(1,1); 154 for(int i=1;i<=m;i++) 155 { 156 int f=LCA(sta[i],fin[i]); 157 int x=sta[i]; 158 int rt=p[sta[i]].dp; 159 while(p[x].top!=p[f].top) 160 { 161 Tr_add(p[p[x].top].ind,p[x].ind,1,n,rtu[rt],1); 162 x=p[p[x].top].fa; 163 } 164 Tr_add(p[f].ind,p[x].ind,1,n,rtu[rt],1); 165 Tr_add(p[f].ind,p[f].ind,1,n,rtu[rt],-1); 166 x=fin[i]; 167 rt=N+p[sta[i]].dp-2*p[f].dp; 168 while(p[x].top!=p[f].top) 169 { 170 Tr_add(p[p[x].top].ind,p[x].ind,1,n,rtd[rt],1); 171 x=p[p[x].top].fa; 172 } 173 Tr_add(p[f].ind,p[x].ind,1,n,rtd[rt],1); 174 } 175 for(int i=1;i<=n;i++) 176 { 177 int dowsid=Tr_val(p[i].ind,rtd[N+p[i].w-p[i].dp],1,n); 178 int upsid=Tr_val(p[i].ind,rtu[p[i].dp+p[i].w],1,n); 179 printf("%d ",dowsid+upsid); 180 } 181 return 0; 182 }