【uoj261】 天天爱跑步

http://uoj.ac/problem/261 (题目链接)

题意

  给出一棵树,给出一些起点和终点,没走一条路径耗费时间1,每个节点上有一个权值w,问有多少条路径经过这个节点时所用的时间恰好是w。

Solution

  转自:http://blog.csdn.net/haarmony/article/details/53259338

  约定第${i}$个人起终点的${lca(s[i],t[i])}$为${lca[i]}$,点${i}$深度为${deep[i]}$

  • 考虑可能对点${u}$有贡献的第${i}$个跑步者,${lca[i]}$肯定在${u}$或者${u}$上方,否则不经过${u}$点,即${lca[i]==u || lca[i]∉subtree[u]}$
  • 基于此前提,只有两种情况(有重合部分):${s[i]∈subtree[u]}$,${t[i]∈subtree[u]}$ 
    分类讨论能被${u}$看见的点${v}$的情况 
      1.${v}$为${i}$人起点${s[i]}$:${deep[s[i]]-w[u]==dep[u]}$ 
      2.${v}$为${i}$人终点${t[i]}$:${deep[s[i]]+deep[t[i]]-2*deep[lca[i]]-(deep[t[i]]-deep[u])==w[u]}$,即${deep[s[i]]-2*deep[lca[i]]==w[u]-deep[u]}$

  我们发现如果做个变换,即${deep[u]+w[u]==deep[s[i]]}$

  与${w[u]-deep[u]==deep[s[i]]-2*deep[lca[i]]}$的话,式子右边是不变的,那是不是可以开一个${cnt}$数组来统计一下子树中等于右式的出发点和结束点的个数呢?

    • 考虑使用${cnt[2][600600]}$存储起点/终点的${deep[s[i]]}$/${deep[s[i]]-2*deep[lca[i]]}$等于${j}$的点的数量,保存在数组${cnt[0
      or 1][j]}$中,那么当dfs中当前点到${u}$的时候,${ans[u]}$就可以从cnt数组中得到,特殊情况是:${u}$为第${i}$人的lca时可能导致${s[i]}$与${t[i]}$各对${ans[u]}$贡献一次,所以式子如下
    • ${ans[u]=cnt[0][dep[u]+w[u]]+cnt[0][w[u]-dep[u]]-重复部分}$。两下标为上面两个等式的左式,需要注意的是${dep[s[i]]-2*dep[lca[i]]}$有可能是负数,下标可以统一+300000处理成正数(否则挂成50分)。其中重复部分可以在消除lca标记的时候判掉。
    • 维护cnt数组的方式容易想到就是在${s[i],t[i],lca[i]}$上打标记,若当前点为${s[i]}$就计入${cnt[0][dep[s[i]]]}$,${t[i]}$同理,${lca[i]}$就把两个标记再退出去
    • 然而如果对于每颗子树建立一个cnt,再把cnt合并的话,复杂度是n^2的。于是发现搜到以v为根的子树时后,对v贡献的只有两个下标,那么在搜索点v前,传两个参数a,b记录一下原来的cnt两个值,dfs(v,a,b)${ans[v]-=a+b}$即可

细节

  细节很多,想清楚再写。

代码

// uoj261
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define inf 2147483640
#define LL long long
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int T=300000,maxn=300010;
struct edge {int to,next;}e[maxn<<1],g[maxn],ct[maxn];
int cnt[2][10000010],h[maxn],hh[maxn],head[maxn];
int deep[maxn],fa[maxn][30],bin[30],Lca[maxn];
int n,m,c1,c2,c3,ans[maxn],cs[maxn],w[maxn],s[maxn],t[maxn];

void linke(int u,int v) {
	e[++c1].to=v;e[c1].next=head[u];head[u]=c1;
	e[++c1].to=u;e[c1].next=head[v];head[v]=c1;
}
void linkg(int u,int v) {g[++c2].to=v;g[c2].next=h[u];h[u]=c2;}
void linkt(int u,int v) {ct[++c3].to=v;ct[c3].next=hh[u];hh[u]=c3;}

void dfs(int x) {
	for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
			fa[e[i].to][0]=x;
			deep[e[i].to]=deep[x]+1;
			dfs(e[i].to);
		}
}
int lca(int x,int y) {
	if (deep[x]<deep[y]) swap(x,y);
	int t=deep[x]-deep[y];
	for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
	for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return x==y ? x : fa[x][0];
}
void dfs(int x,int ta,int tb) {
	for (int j,i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
			j=e[i].to;
			dfs(j,cnt[0][w[j]+deep[j]+T],cnt[1][w[j]-deep[j]+T]);
		}
	cnt[0][deep[x]+T]+=cs[x];
	for (int j,i=hh[x];i;i=ct[i].next) {
		j=ct[i].to;
		cnt[1][deep[s[j]]-deep[Lca[j]]*2+T]++;
	}
	ans[x]+=cnt[0][w[x]+deep[x]+T]+cnt[1][w[x]-deep[x]+T]-ta-tb;
	for (int j,i=h[x];i;i=g[i].next) {
		j=g[i].to;
		if (w[x]+deep[x]==deep[s[j]]) ans[x]--;
		cnt[0][deep[s[j]]+T]--;cnt[1][deep[s[i]]-2*deep[x]+T]--;
	}
}
int main() {
	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
	scanf("%d%d",&n,&m);
	for (int u,v,i=1;i<n;i++) {
		scanf("%d%d",&u,&v);
		linke(u,v);
	}
	dfs(1);
	for (int i=1;i<=n;i++) scanf("%d",&w[i]);
	for (int i=1;i<=m;i++) {
		scanf("%d%d",&s[i],&t[i]);
		Lca[i]=lca(s[i],t[i]);cs[s[i]]++;
		linkg(Lca[i],i);
		linkt(t[i],i);
	}
	dfs(1,0,0);
	for (int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}

  

时间: 2024-12-11 22:43:36

【uoj261】 天天爱跑步的相关文章

UOJ261 【NOIP2016】天天爱跑步

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.天天爱跑步是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结

【NOIP2016】天天爱跑步(树上差分)

题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该

天天爱跑步[NOIP2016]

时间限制:2 s   内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到n的连续正整数. 现在有m个玩家,第i个玩家的起点为Si,终点为Ti.每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发,以每秒跑一条边的速度,不间断

bzoj4719[Noip2016]天天爱跑步

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去, 跑到

noip 2016 天天爱跑步

描述 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一棵包含n个结点和n - 1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到n的连续正整数. 现在有m个玩家,第i个玩家的起点为Si,终点为Ti.每天打卡任务开始时,所有玩家 在第0秒 同时从 自己的起点 出发,以 每秒跑一条边 的速度,不间断地沿着最短路径向着 自己的终点 跑去,

Noip 2016 天天爱跑步 【树上倍增+深搜】

题目: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点和 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从到的连续正整数. 现在有个玩家,第个玩家的起点为 ,终点为 .每天打卡任务开始时,所有玩家在第秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务.

bzoj 4719: [Noip2016]天天爱跑步

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去

Noip2016day1 天天爱跑步running

题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点和 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从到的连续正整数. 现在有个玩家,第个玩家的起点为 ,终点为  .每天打卡任务开始时,所有玩家在第秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务

NOIP2016天天爱跑步

2557. [NOIP2016]天天爱跑步 时间限制:2 s   内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到n的连续正整数. 现在有m个玩家,第i个玩家的起点为Si,终点为Ti.每天打卡任务开始时,所有玩家在第0秒同时从

LCA+线段树 NOIP2016 天天爱跑步

天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn个结点和 n?1n-1n?1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从111到nnn的连续正整数. 现在有mmm个玩家,第iii个玩家的起点为 SiS_iS?i??,终点为 TiT_iT?i?? .每天打卡任务开始时,所有玩家在第000秒同时从自己的起点出