NOIP 2016 天天爱跑步 80分暴力
题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 个结点和 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从到的连续正整数。
现在有个玩家,第个玩家的起点为 ,终点为 。每天打卡任务开始时,所有玩家在第秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第秒也理到达了结点 。 小C想知道每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点作为终点的玩家: 若他在第秒重到达终点,则在结点的观察员不能观察到该玩家;若他正好在第秒到达终点,则在结点的观察员可以观察到这个玩家。
输入输出格式
输入格式:
第一行有两个整数和 。其中代表树的结点数量, 同时也是观察员的数量, 代表玩家的数量。
接下来 行每行两个整数和 ,表示结点 到结点 有一条边。
接下来一行 个整数,其中第个整数为 , 表示结点出现观察员的时间。
接下来 行,每行两个整数,和,表示一个玩家的起点和终点。
对于所有的数据,保证 。
输出格式:
输出1行 个整数,第个整数表示结点的观察员可以观察到多少人。
输入输出样例
6 3 2 3 1 2 1 4 4 5 4 6 0 2 5 1 2 3 1 5 1 3 2 6
2 0 0 1 1 1
5 3 1 2 2 3 2 4 1 5 0 1 0 3 0 3 1 1 4 5 5
1 2 1 0 1
说明
【样例1说明】
对于1号点,,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。
对于4号点,玩家1被观察到,共1人被观察到。
对于5号点,玩家1被观察到,共1人被观察到。
对于6号点,玩家3被观察到,共1人被观察到。
【子任务】
每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。
【提示】
如果你的程序需要用到较大的栈空问 (这通常意味着需要较深层数的递归), 请务必仔细阅读选手日录下的文本当rumung:/stact.p″, 以了解在最终评测时栈空问的限制与在当前工作环境下调整栈空问限制的方法。
在最终评测时,调用栈占用的空间大小不会有单独的限制,但在我们的工作
环境中默认会有 8 MB 的限制。 这可能会引起函数调用层数较多时, 程序发生
栈溢出崩溃。
我们可以使用一些方法修改调用栈的大小限制。 例如, 在终端中输入下列命
令 ulimit -s 1048576
此命令的意义是,将调用栈的大小限制修改为 1 GB。
例如,在选手目录建立如下 sample.cpp 或 sample.pas
将上述源代码编译为可执行文件 sample 后,可以在终端中运行如下命令运
行该程序
./sample
如果在没有使用命令“ ulimit -s 1048576”的情况下运行该程序, sample
会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。
特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们
运行该命令。
请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内
存共同受到内存限制。
思路:
这题真特么恶心;
明明noi难度的题非要搞到noip里;
这题一看范围就懵了;
然后,我们就开始写暴力;
看第一个数据,n<=1000;
恩,纯暴力就好,找两点的lca,往上跳的同时观察;
看第二个数据,树退化成了链;
按说树退化成了链,应该是更好做一些,然而,蒟蒻不会;
最后蒟蒻的做法是
枚举每个点;
每个点的可以被观察到时,这条路径的起点是却定的;
所以,我们只需判断这个起点的路径是否包括这个点;
可能被极限数据卡成n*n,但是出题人还是很良心的;
看第三个数据,路径起点都是1;
当起点都是1的时候;
对整棵树以1为根开始树剖;
然后,我们就发现,每个点的深度就是这个点上的人跑的时间;
然后判断wi是否等于deepi就好;
看第4个数据,路径终点都是1;
这个就有点恶心了;
但是我还是拿到了手;
我们先进行dfs,把树上每个节点的子树都用区间表示;
然后针对每个深度建立一颗线段树;
然后,用当树为链时判断起点的方法判断起点在哪个深度;
然后用线段树logn求出;
恩,水到80分了;
剩下20分死活水不出来;
来,上代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 100005 #define maxn1 1005 //暴力dfs #define maxn2 99994 //树变成一条链 #define maxn3 99995 //所有si=1 #define maxn4 99996 //所有ti=1 using namespace std; struct STreeNodeType { int l,r,dis,lc,rc; }; struct STreeNodeType stree[maxn*19]; struct TreeNodeType { int l,r,dis,mid,flag; }; struct TreeNodeType tree[maxn<<2]; struct ListType { int e,v; }; struct ListType eli[maxn]; int root[maxn],li[maxn],ri[maxn]; int n,m,head[maxn],E[maxn<<1],V[maxn<<1],cnt,apti[maxn]; int f[maxn],deep[maxn],dfn[maxn],fdfn,times[maxn],tot; int lis[maxn],size[maxn],top[maxn],bel[maxn],id[maxn]; char Cget; inline void in(int &now) { now=0,Cget=getchar(); while(Cget>'9'||Cget<'0') Cget=getchar(); while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } } void dfs_dfn(int now,int fa) { f[now]=fa,deep[now]=deep[fa]+1,dfn[now]=++fdfn; for(int i=head[now];i;i=E[i]) { if(V[i]==fa) continue; dfs_dfn(V[i],now); } } inline void slca(int x,int y) { int x_=x,y_=y,lca,ti=0; while(dfn[x_]!=dfn[y_]) { if(dfn[x_]<dfn[y_]) swap(x_,y_); while(dfn[x_]>dfn[y_]) x_=f[x_]; } lca=x_; while(x!=lca) { if(ti==apti[x]) times[x]++; x=f[x],ti++; } if(ti==apti[lca]) times[lca]++; ti+=deep[y]-deep[lca]; while(y!=lca) { if(ti==apti[y]) times[y]++; y=f[y],ti--; } } void dfs_tree(int now,int fa) { int pos=cnt++; f[now]=fa; deep[now]=deep[fa]+1; for(int i=head[now];i;i=E[i]) { if(V[i]==fa) continue; dfs_tree(V[i],now); } size[now]=cnt-pos; } void dfs_tree_(int now,int chain) { int pos=0; top[now]=chain,bel[++cnt]=now,id[now]=cnt; for(int i=head[now];i;i=E[i]) { if(V[i]==f[now]) continue; if(size[V[i]]>size[pos]) pos=V[i]; } if(pos==0) return ; dfs_tree_(pos,chain); for(int i=head[now];i;i=E[i]) { if(V[i]==pos||V[i]==f[now]) continue; dfs_tree_(V[i],V[i]); } } inline void tree_down(int now) { if(tree[now].l==tree[now].r) return ; tree[now<<1].flag+=tree[now].flag; tree[now<<1|1].flag+=tree[now].flag; tree[now<<1].dis+=tree[now].flag*(tree[now<<1].r-tree[now<<1].l+1); tree[now<<1|1].dis+=tree[now].flag*(tree[now<<1|1].r-tree[now<<1|1].l+1); tree[now].flag=0; } void tree_build(int now,int l,int r) { tree[now].l=l,tree[now].r=r; if(l==r) return ; tree[now].mid=l+r>>1; tree_build(now<<1,l,tree[now].mid); tree_build(now<<1|1,tree[now].mid+1,r); } void tree_change(int now,int l,int r) { if(tree[now].l==l&&tree[now].r==r) { tree[now].flag++; tree[now].dis+=r-l+1; return ; } if(tree[now].flag) tree_down(now); if(l>tree[now].mid) tree_change(now<<1|1,l,r); else if(r<=tree[now].mid) tree_change(now<<1,l,r); else { tree_change(now<<1,l,tree[now].mid); tree_change(now<<1|1,tree[now].mid+1,r); } tree[now].dis=tree[now<<1].dis+tree[now<<1|1].dis; } void solve_add(int x,int y) { while(top[x]!=top[y]) { if(deep[x]<deep[y]) swap(x,y); tree_change(1,id[top[x]],id[x]); x=f[top[x]]; } if(deep[x]>deep[y]) swap(x,y); tree_change(1,id[x],id[y]); } void tree_count_si(int now) { if(tree[now].l==tree[now].r) { if(deep[bel[tree[now].l]]==apti[bel[tree[now].l]]) { times[bel[tree[now].l]]+=tree[now].dis; } return ; } if(tree[now].flag) tree_down(now); tree_count_si(now<<1); tree_count_si(now<<1|1); } void st_add(int &now,int l,int r,int to,int x) { if(now==0) { now=++tot; stree[now].l=l,stree[now].r=r; } stree[now].dis+=x; if(l==r) return ; int mid=l+r>>1; if(to>mid) st_add(stree[now].rc,mid+1,r,to,x); else st_add(stree[now].lc,l,mid,to,x); } void dfs_ti(int now,int fa) { li[now]=++cnt,deep[now]=deep[fa]+1; st_add(root[deep[now]],1,n,li[now],size[now]); for(int i=head[now];i;i=E[i]) { if(V[i]==fa) continue; dfs_ti(V[i],now); } ri[now]=cnt; } int query(int now,int l,int r) { if(now==0) return 0; if(stree[now].l==l&&stree[now].r==r) return stree[now].dis; int mid=stree[now].l+stree[now].r>>1; if(l>mid) return query(stree[now].rc,l,r); else if(r<=mid) return query(stree[now].lc,l,r); else return query(stree[now].lc,l,mid)+query(stree[now].rc,mid+1,r); } int main() { in(n),in(m);int u,v; for(int i=1;i<n;i++) { in(u),in(v); V[++cnt]=v,E[cnt]=head[u],head[u]=cnt; V[++cnt]=u,E[cnt]=head[v],head[v]=cnt; } for(int i=1;i<=n;i++) in(apti[i]); if(n<=maxn1) { dfs_dfn(1,0); while(m--) { in(u),in(v); slca(u,v); } for(int i=1;i<=n;i++) printf("%d ",times[i]); }else if(n==maxn2) { cnt=0; while(m--) { in(u),in(v); eli[++cnt].v=v,eli[cnt].e=lis[u],lis[u]=cnt; } for(int i=1;i<=n;i++) { u=i-apti[i],v=i+apti[i]; if(u>0) { for(int j=lis[u];j;j=eli[j].e) { if(eli[j].v>=i) times[i]++; } } if(v<=n) { for(int j=lis[v];j;j=eli[j].e) { if(eli[j].v<=i) times[i]++; } } printf("%d ",times[i]); } }else if(n==maxn3) { deep[0]=-1; cnt=0,dfs_tree(1,0); cnt=0,dfs_tree_(1,1); tree_build(1,1,n); while(m--) { in(u),in(v); solve_add(u,v); } tree_count_si(1); for(int i=1;i<=n;i++) printf("%d ",times[i]); }else if(n==maxn4) { while(m--) { in(u),in(v); size[u]++; } deep[0]=0; cnt=0,tot=0,dfs_ti(1,0); for(int i=1;i<=n;i++) { int pos=deep[i]+apti[i]; printf("%d ",query(root[pos],li[i],ri[i])); } } return 0; }