【FOJ2207 11月月赛C】【DFS栈性质应用 离线处理】以撒的结合 从x到y路径上的第k个点 询问众多

原创 2015年11月18日 21:21:15
 Problem 2207 以撒的结合

Accept: 30    Submit: 98
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

小茗同学最近在认真地准备比赛,所以经常玩以撒的结合。

《以撒的结合》是一款由Edmund McMillen,Florian Himsl 开发,并由Edmund McMillen最早于2011年09月29日发行的一款2D平面角色扮演、动作冒险类的独立游戏。游戏的角色将在有着能够提升能力的道具与特殊技能的半RPG世界中闯荡。

——来自百度百科

小茗同学在打BOSS前,费掉了很多HP。在地图的一些房间里有补充HP的红心,然而小茗同学受到了看不见地图的诅咒。凭借不知道哪里来的记忆,小茗同学记得某个有红心的房间在房间A与房间B的路上的第K个房间里。为了简化问题,我们把地图看成一棵树。小茗同学想知道A到B的第K个房间号为多少,由于小茗同学很累,所以现在这个任务交给你了。

 Input

第一行是一个整数T(T<=10),表示有T组测试数据。

每组数据的第一行为两个整数n m(0<n<=1000,0<m<=n*n),分别表示房间个数和询问次数。

接下来n-1行,每行两个整数u v(0<u、v<=n,且u≠v),表示地图上房间u和房间v有一条路径。

最后是m行,每行三个整数u v k,表示询问房间u到房间v的路径上的第k个房间。

输入数据保证合法,即k不超过u、v的最短距离。

 Output

对于每组数据,首先第一行先输出“Case #x:“ ,其中x是从1开始,表示数据组号,接下来m行,每行输出相应的房间号。

 Sample Input

16 31 22 42 51 33 64 6 41 6 24 5 3

 Sample Output

Case #1:335

 Source

FOJ有奖月赛-2015年11月



【FOJ2207 11月月赛C】【DFS栈性质应用 离线处理】以撒的结合 从x到y路径上的第k个点 询问众多 DFS AC

#include<stdio.h> 
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=1010,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,m,x,y,k;
int st,top,tim;
vector<int>a[N];
int first[N][N];int id;
struct query
{
	int k,o,nxt;
}q[N*N];
int e[N],s[N],ans[N*N];
void dfs(int x)
{
	e[x]=tim;
	s[++top]=x;
	for(int z=first[st][x];z;z=q[z].nxt)
	{
		int k=q[z].k;
		int o=q[z].o;
		ans[o]=s[k];
	}
	first[st][x]=0;
	for(int i=a[x].size()-1;~i;--i)
	{
		int y=a[x][i];
		if(e[y]!=tim)dfs(y);
	}
	--top;
}
int main()
{
	scanf("%d",&casenum);
	for(casei=1;casei<=casenum;casei++)
	{
		scanf("%d%d",&n,&m);
		if(n>1000||m>n*n)return 0;
		for(int i=1;i<=n;i++)a[i].clear();
		for(int i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			a[x].push_back(y);
			a[y].push_back(x);
		}
		id=0;for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&x,&y,&k);
			++id;
			q[id].k=k;
			q[id].o=i;
			q[id].nxt=first[x][y];
			first[x][y]=id;
		}
		for(st=1;st<=n;st++)
		{
			++tim;
			dfs(st);
		}
		printf("Case #%d:\n",casei);
		for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	}
	return 0;
}
/*
【trick&&吐槽】
1,不看数据规模就做真的是好蠢好蠢,数据规模也是对做法的提示。
2,dfs上有很多精妙的性质和应用。
3,lca问题我竟然忘记了要把双向边都放进去+_+,然而竟然能过样例,天哪

【题意】
给你一棵树,树上有n(1e3)个点。
我们有m个询问,m最大为n*n。
对于每个询问,给你(x,y,k),问你从x到y上的第k个房间的是多少。

【类型】
LCA or 树链剖分?NO!正解是栈性质dfs!

【分析】
这题我一看到是树结构,立马想到树链剖分或者是LCA这样O(mlogn)的做法。
然而m实在是太大了,这个做法只会造成TLE >_<
正解是怎么做呢?DFS!
我们用vector存下所有询问(x,y,k)
[哇哇哇,vector太大也会导致TLE!换成链表模式就AC了>_<]
然后从每个点开始dfs,用栈存下所有点。
如果遇到(x,y,k)的询问,我们就直接记录答案为目前从x开始dfs的栈中第k个点。
这样就可以AC喽~

【时间复杂度&&优化】
O(n^2)

*/

【FOJ2207 11月月赛C】【DFS栈性质应用 离线处理】以撒的结合 从x到y路径上的第k个点 询问众多 LCA TLE

#include<stdio.h> 
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=1010,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,m,x,y,k;
vector<int>a[N];
int d[N];
int f[N][12];
int b[12];
void dfs(int x)
{
	for(int i=a[x].size()-1;~i;--i)
	{
		int y=a[x][i];
		if(y==f[x][0])continue;
		f[y][0]=x;
		d[y]=d[x]+1;
		dfs(y);
	}
}
void LCAinit()
{
	for(int j=1;b[j]<n;j++)
	{
		for(int i=1;i<=n;i++)if(~f[i][j-1])
		{
			f[i][j]=f[f[i][j-1]][j-1];
		}
	}
}
int DX,DY;
int LCA(int x,int y)
{
	int i,j;
	if(d[x]<d[y])swap(x,y);
	for(i=0;b[i]<=d[x];i++);i--;
	for(j=i;d[x]>d[y];j--)if(d[x]-b[j]>=d[y])x=f[x][j];
	if(x==y)return x;
	for(j=i;f[x][0]!=f[y][0];j--)if(f[x][j]!=f[y][j])
	{
		x=f[x][j];
		y=f[y][j];
	}
	return f[x][0];
}
int find(int x,int dis)
{
	int i;
	for(i=0;b[i]<=dis;i++);i--;
	while(dis)
	{
		if(dis>=b[i])
		{
			x=f[x][i];
			dis-=b[i];
		}
	}
	return x;
}
int main()
{
	for(int i=0;i<=10;i++)b[i]=1<<i;
	scanf("%d",&casenum);
	for(casei=1;casei<=casenum;casei++)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)a[i].clear();
		for(int i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			a[x].push_back(y);
			a[y].push_back(x);
		}
		MS(f,-1);
		f[1][0]=0;d[1]=0;dfs(1);
		LCAinit();
		printf("Case #%d:\n",casei);
		while(m--)
		{
			scanf("%d%d%d",&x,&y,&k);k--;
			int lca=LCA(x,y);
			int dx=d[x]-d[lca];
			int dy=d[y]-d[lca];
			int ans;
			if(dx>=k)ans=find(x,k);
			else{k-=dx;ans=find(y,dy-k);}
			printf("%d\n",ans);
		}
	}
	return 0;
}
/*
【trick&&吐槽】
1,不看数据规模就做真的是好蠢好蠢,数据规模也是对做法的提示。
2,dfs上有很多精妙的性质和应用。
3,lca问题我竟然忘记了要把双向边都放进去+_+,然而竟然能过样例,天哪

【题意】
给你一棵树,树上有n(1e3)个点。
我们有m个询问,m最大为n*n。
对于每个询问,给你(x,y,k),问你从x到y上的第k个房间的是多少。

【类型】
LCA or 树链剖分?NO!正解是栈性质dfs!

【分析】
这题我一看到是树结构,立马想到树链剖分或者是LCA这样O(mlogn)的做法。
然而m实在是太大了,这个做法只会造成TLE >_<
正解是怎么做呢?DFS!
我们用vector存下所有询问(x,y,k)
[哇哇哇,vector太大也会导致TLE!换成链表模式就AC了>_<]
然后从每个点开始dfs,用栈存下所有点。
如果遇到(x,y,k)的询问,我们就直接记录答案为目前从x开始dfs的栈中第k个点。
这样就可以AC喽~

【时间复杂度&&优化】
O(n^2)

*/


版权声明:题解中哪里写错请一定要指出来QwQ 转载还请注明下出处哦,谢谢^_^

bzoj 2301: [HAOI2011]Problem b

Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。 Inp...
  • lqybzx
  • lqybzx
  • 2014年10月28日 21:12
  • 682

BZOJ-2301-[HAOI2011]Problem b

ACM模版[HAOI2011]Problem b描述对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。...
  • f_zyj
  • f_zyj
  • 2016年07月07日 19:24
  • 502

[bzoj 2301--HAOI2011]Problem b

对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。 bzoj 1101的升级版,有了下限。建...
  • lixuanjing2016
  • lixuanjing2016
  • 2017年12月05日 14:57
  • 190

BZOJ 2301 Problem B(x属于[a,b],y属于[c,d]满足gcd(x,y)=k的(x,y)的有序对数)

题目链接: BZOJ 2301 Problem B 题意: 区间x∈[a,b],y∈[c,d]满足gcd(x,y)=k的(x,y)的对数x\in [a,b],y \in[c,d]满足gcd(x,...
  • Ramay7
  • Ramay7
  • 2016年06月04日 14:01
  • 566

蓝桥杯-算法训练-ALGO1-区间k大数查询

JAVA-蓝桥杯-算法训练-区间k大数查询 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。 输入格式 第一行包含一个数n,表示序列...
  • u011035622
  • u011035622
  • 2015年02月07日 15:16
  • 1027

JZOJ4444【HNOI模拟】a

Description给定一棵N 个节点的树, 每个点i 有权值a[i], 1
  • doyouseeman
  • doyouseeman
  • 2016年04月19日 18:08
  • 783

12.9省选训练总结

dp的优化
  • Demon_Rieman
  • Demon_Rieman
  • 2017年12月10日 21:22
  • 48

笔试面试13--给定 x, k ,求满足 x + y = x | y 的第 k 小的正整数 y

给定 x, k ,求满足 x + y = x | y 的第 k 小的正整数 y 。 | 是二进制的或(or)运算,例如 3 | 5 = 7。比如当 x=5,k=1时返回 2,因为5+1=6 不等于 5...
  • WQP_Ya_Ping
  • WQP_Ya_Ping
  • 2016年05月19日 17:39
  • 1108

【bzoj2588】Spoj 10628. Count on a tree LCA+主席树

Description给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为...
  • LOI_DQS
  • LOI_DQS
  • 2016年03月19日 00:34
  • 394

问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。 输入格式 第一行包含一个数n,表示序列长度。 第二行包含n个正整数,表示给定的序列。 第三个包含一个正整数m,表

#include using namespace std; void print(int *a,int len) { int i=0; for(;i cout cout } void...
  • Faded0104
  • Faded0104
  • 2016年12月30日 20:14
  • 2517
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【FOJ2207 11月月赛C】【DFS栈性质应用 离线处理】以撒的结合 从x到y路径上的第k个点 询问众多
举报原因:
原因补充:

(最多只允许输入30个字)