NOIP 2016 Day1 T2 天天爱跑步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP 2016 Day1 T2 天天爱跑步相关的知识,希望对你有一定的参考价值。

题目大意

给定一个n个节点,n?1条边的树。有m个玩家,第i个玩家从xi走树上最短路径到yi。玩家第0秒在自己的起点上,然后每秒移动一条边,移动到终点后结束移动。 
每个节点上有一个观察员以及权值wi。如果有一个玩家在其移动的第wi恰好到达这个点,那么这个点上的观察员就会观察到他(如果这个点是终点,且玩家在wi秒之前到达不算)。 
求每个点上的观察员分别观察到了多少个玩家。

1n299998,1m299998

题目分析

我们将每条路径拆成从出发点到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),动态开点)。然后将标记挂在lcay的儿子那里(为了避免算重)。然后在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 天天爱跑步的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 2016 Day1 T2 天天爱跑步

Noip2016day1 天天爱跑步running

$NOIP 2016 Day1$ 模拟考试 题解报告

计蒜客NOIP模拟赛4 D2T2 跑步爱天天

NOIP2016天天爱跑步

Noip 2016 天天爱跑步 题解