NOIP 2016 Day1 T2 天天爱跑步
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP 2016 Day1 T2 天天爱跑步相关的知识,希望对你有一定的参考价值。
题目大意
给定一个n个节点,n?1条边的树。有m个玩家,第i个玩家从xi走树上最短路径到yi。玩家第0秒在自己的起点上,然后每秒移动一条边,移动到终点后结束移动。
每个节点上有一个观察员以及权值wi。如果有一个玩家在其移动的第wi秒恰好到达这个点,那么这个点上的观察员就会观察到他(如果这个点是终点,且玩家在wi秒之前到达不算)。
求每个点上的观察员分别观察到了多少个玩家。
1≤n≤299998,1≤m≤299998
题目分析
我们将每条路径拆成从出发点到lca,和从lca的下一个点到结束点两段。
对于第一段,如果在点i时被观察到,我们可以写出deep(x)?deep(i)=wi。因此我们对所有deep(x)开权值线段树(下标为DFN(x),动态开点),在每个玩家路径lca处挂一个在deep(x)的权值线段树中DFN(x)位置权值+1的标记。然后每访问一个点就要先处理该点的所有标记,在deep(i)+wi的权值线段树里面查询子树的权值和。但是因为在lca上面的点就不能观察到这个点,因此退出一个点时要撤销上面的标记。
对于第二段,如果点i时被观察到了,我们可以写出deep(x)+deep(i)?2deep(lca(x,i))=wi,和上面类似,那么我们对所有路径的deep(x)?2deep(lca(x,y))开权值线段树(依然下标为DFN(x),动态开点)。然后将标记挂在lca靠y的儿子那里(为了避免算重)。然后在wi?deep(i)的权值线段树中查询。
这样就要实现一个倍增和常数比较大的权值线段树, 时间复杂度O(nlog2n)。
听说CCF老爷机要卡log算法的常,那我也没办法了。
update:将我的权值线段树改成桶就可以O(n)了QwQ。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<cctype> 5 #include<cmath> 6 using namespace std; 7 int buf[30]; 8 const int N=300050; 9 const int LGN=19; 10 const int M=300050; 11 const int E=N<<1; 12 const int Q=M<<1; 13 struct query{ 14 bool tp; 15 int key,x; 16 }qy[Q]; 17 int qnxt[Q]; 18 struct D{ 19 int key,x,y,lab; 20 }srt[M]; 21 int d; 22 bool operator<(D a,D b){return a.key<b.key;} 23 struct segment_tree 24 { 25 int sum[N*20],son[N*20][2],root[M]; 26 int tot; 27 int newnode() 28 { 29 sum[++tot]=0; 30 son[tot][0]=son[tot][1]=0; 31 return tot; 32 } 33 void update(int x){sum[x]=sum[son[x][0]]+sum[son[x][1]];} 34 void modify(int &x,int y,int l,int r,int delta) 35 { 36 if (!x) x=newnode(); 37 if (l==r) 38 { 39 sum[x]+=delta; 40 return; 41 } 42 int mid=l+r>>1; 43 if (y<=mid) modify(son[x][0],y,l,mid,delta); 44 else modify(son[x][1],y,mid+1,r,delta); 45 update(x); 46 } 47 int query(int x,int st,int en,int l,int r) 48 { 49 if (!x) return 0; 50 if (st==l&&en==r) return sum[x]; 51 int mid=l+r>>1; 52 if (en<=mid) return query(son[x][0],st,en,l,mid); 53 else if (mid+1<=st) return query(son[x][1],st,en,mid+1,r); 54 else return query(son[x][0],st,mid,l,mid)+query(son[x][1],mid+1,en,mid+1,r); 55 } 56 }t[2]; 57 int deep[N],last[N],size[N],DFN[N],qlst[N],w[N],ans[N]; 58 int tov[E],nxt[E],fa[N][LGN]; 59 int n,m,tot,idx,lgn,cnt,dif; 60 void insert(int x,int y){tov[++tot]=y,nxt[tot]=last[x],last[x]=tot;} 61 void hang(int x,int y){qnxt[y]=qlst[x],qlst[x]=y;} 62 void dfs(int x)// 处理深度 以及 fa数组 63 { 64 DFN[x]=++idx,size[x]=1; 65 for(int i=last[x],y;i;i=nxt[i]) 66 if((y=tov[i])!=fa[x][0]) 67 fa[y][0]=x,deep[y]=deep[x]+1,dfs(y),size[x]+=size[y]; 68 } 69 void pre() 70 { 71 for(int j=1;(1<<j)<=n;j++) 72 for(int i=1;i<=n;i++) 73 fa[i][j]=fa[fa[i][j-1]][j-1]; 74 } 75 int adjust(int x,int d) 76 { 77 for (int i=lgn;i>=0;i--) if (deep[fa[x][i]]>=d) x=fa[x][i]; 78 return x; 79 } 80 int lca(int x,int y) 81 { 82 if (deep[x]>deep[y]) swap(x,y); 83 y=adjust(y,deep[x]); 84 if (x==y) return x; 85 for (int i=lgn;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; 86 return fa[x][0]; 87 } 88 void proc() 89 { 90 sort(srt+1,srt+1+d); 91 dif=0,srt[0].key=-n*2; 92 for (int i=1;i<=d;i++) 93 { 94 dif+=srt[i].key!=srt[i-1].key; 95 srt[i].lab=dif; 96 qy[++cnt].tp=1,qy[cnt].key=dif,qy[cnt].x=srt[i].y; 97 hang(srt[i].x,cnt); 98 } 99 } 100 query tmp; 101 int search(int aim) 102 { 103 int ret=0; 104 int l=1,r=d,mid; 105 while (l<=r) 106 { 107 mid=l+r>>1; 108 if (srt[mid].key<=aim) ret=mid,l=mid+1; 109 else r=mid-1; 110 } 111 if (srt[ret].key==aim) return srt[ret].lab; 112 return 0; 113 } 114 void calc(int x) 115 { 116 for (int i=qlst[x];i;i=qnxt[i]) 117 { 118 tmp=qy[i]; 119 t[tmp.tp].modify(t[tmp.tp].root[tmp.key],DFN[tmp.x],1,n,1); 120 } 121 for (int i=last[x],y;i;i=nxt[i]) 122 if ((y=tov[i])!=fa[x][0]) calc(y); 123 ans[x]=0; 124 if (w[x]+deep[x]<=n) ans[x]+=t[0].query(t[0].root[w[x]+deep[x]],DFN[x],DFN[x]+size[x]-1,1,n); 125 int f=search(deep[x]-w[x]); 126 if (f) ans[x]+=t[1].query(t[1].root[f],DFN[x],DFN[x]+size[x]-1,1,n); 127 for (int i=qlst[x];i;i=qnxt[i]) 128 { 129 tmp=qy[i]; 130 t[tmp.tp].modify(t[tmp.tp].root[tmp.key],DFN[tmp.x],1,n,-1); 131 } 132 } 133 int main() 134 { 135 scanf("%d%d",&n,&m); 136 for (int i=1,x,y;i<n;i++) 137 { 138 scanf("%d%d",&x,&y); 139 insert(x,y),insert(y,x); 140 } 141 fa[1][0]=0,deep[1]=1,dfs(1),pre(); 142 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 143 for(int x,y,z;m--;) 144 { 145 scanf("%d%d",&x,&y);z=lca(x,y); 146 qy[++cnt].tp=0,qy[cnt].key=deep[x],qy[cnt].x=x; 147 hang(z,cnt); 148 if(!(DFN[y]<=DFN[x]&&DFN[x]<=DFN[y]+size[y]-1)) 149 srt[++d].key=deep[z]*2-deep[x],srt[d].x=adjust(y,deep[z]+1),srt[d].y=y; 150 } 151 proc(),calc(1); 152 for (int i=1;i<n;i++) printf("%d ",ans[i]); 153 printf("%d\n",ans[n]); 154 return 0; 155 }
以上是关于NOIP 2016 Day1 T2 天天爱跑步的主要内容,如果未能解决你的问题,请参考以下文章