首页 > 代码库 > timus 1613. For Fans of Statistics【该题超时的代码记录】

timus 1613. For Fans of Statistics【该题超时的代码记录】

该题的意思:按编号递增给出n(0<n<70000)个点的值(点的编号从1~n),给出m(1<=m<70000)条查询数据

数据输入格式为a b c(从编号a到编号b之间是否有值是为c的,如果有则返回1,没有返回0

具体的意思可以进链接: http://acm.timus.ru/problem.aspx?space=1&num=1613

这里只给出超时的代码(可能这道题C++解决真的得用上STL):

case 1:

/*
树的子节点最多三个
左边的子节点(left)表示小于根节点的值的编号
右边的子节点(right)表示大于根节点的值的编号
中间的子节点(mid)表示等于根节点的值的编号
树分插入(insert)和查询(search)操作
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
struct Node
{
	int key,left,right,mid;
};
Node nn[70007];
int n,m,a,b,c;
void insert(int x,int y)
{
	if(nn[x].key>nn[y].key)
	{
		if(nn[y].right!=-1)insert(x,nn[y].right);
		else nn[y].right=x;
	}
	else if(nn[x].key<nn[y].key)
	{
		if(nn[y].left!=-1)insert(x,nn[y].left);
		else nn[y].left=x;
	}
	else
	{
		if(nn[y].mid!=-1)insert(x,nn[y].mid);
		else nn[y].mid=x;
	}
}
bool search(int loc)
{
	if(nn[loc].key>c&&nn[loc].left!=-1)return search(nn[loc].left);
	else if(nn[loc].key>c)return false;
	else if(nn[loc].key<c&&nn[loc].right!=-1)return search(nn[loc].right);
	else if(nn[loc].key<c)return false;
	else
	{
		if(loc>=a&&loc<=b)return true;
		else if(nn[loc].mid!=-1)return search(nn[loc].mid);
		else return false;
	}
}
int main()
{
	int i;
	while(scanf("%d",&n)!=-1)
	{
		for(i=1;i<=n;i++)
			nn[i].key=nn[i].left=nn[i].right=nn[i].mid=-1;
		scanf("%d",&nn[1].key);
		for(i=2;i<=n;i++)
		{
			scanf("%d",&nn[i].key);
			insert(i,1);
		}
		scanf("%d",&m);
		char ch[70007];
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			bool ff=search(1);
			if(ff)ch[i]='1';
			else ch[i]='0';
		}
		ch[m]='\0';
		printf("%s\n",ch);
	}
	return 0;
}

稍稍做了点优化,时间可以稍微快一些的sort+二分查询

case 2:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
struct Node
{
	int key,num;
};
Node nn[70007];
bool cmp(Node aa,Node bb) //排序规则,按照先按键值从小到大排,如果键值相同,则按编号从小到大排序
{
	if(aa.key<bb.key)return true;
	else if(aa.key==bb.key&&aa.num<bb.num)return true;
	return false;
}
int a,b,c,n;
bool find(int st,int ed) 
{
	int i;
	if(st==ed&&nn[st].key==c)
	{
		if(nn[st].num>=a&&nn[st].num<=b)return true;
		if(nn[st].num>=a)  
		{
		  for(i=st-1;i>=0;i--)
			if(nn[i].key!=nn[i+1].key)break;
			else if(nn[i].num>=a&&nn[i].num<=b)return true;
		}
		if(nn[ed].num<=b)
		{
		  for(i=ed+1;i<n;i++)
			if(nn[i].key!=nn[i-1].key)break;
			else if(nn[i].num>=a&&nn[i].num<=b)return true;
		}
	    return false;
	}
	else if(st==ed)return false;
	else if(st+1==ed)
	{
		if(nn[st].num>=a&&nn[st].num<=b&&nn[st].key==c)return true;
		else if(nn[st].key==c&&nn[st].num>=a)
		{
			  for(i=st-1;i>=0;i--)
			    if(nn[i].key!=nn[i+1].key)break;
			    else if(nn[i].num>=a&&nn[i].num<=b)return true;
		}
		if(nn[ed].num>=a&&nn[ed].num<=b&&nn[ed].key==c)return true;
		else if(nn[ed].key==c&&nn[ed].num<=b)
		{
		      for(i=ed+1;i<n;i++)
			   if(nn[i].key!=nn[i-1].key)break;
			   else if(nn[i].num>=a&&nn[i].num<=b)return true;
		}
		return false;
	}
	else if(st+1==ed)return false;
	else
	{
		int mid=(st+ed)/2;
		if(nn[mid].key>c)return find(st,mid-1);
		else if(nn[mid].key<c)return find(mid+1,ed);
		else return find(mid,mid);
	}
}
int main()
{
	int i,m;
	bool ff;
	while(scanf("%d",&n)!=-1)
	{
		for(i=0;i<n;i++)
		{
			scanf("%d",&nn[i].key);
			nn[i].num=i+1;
		}
		sort(nn,nn+n,cmp);
		scanf("%d",&m);
		char ch[70007];
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			ff=find(0,n-1);
			if(ff)ch[i]='1';
			else ch[i]='0';
		}
		ch[m]='\0';
		printf("%s\n",ch);
	}
	return 0;
}
case 2和case 1的优化只是在于键值相同时编号从小到大排序了,所以case 2的find函数里面的多了一点优化。可以这样的优化还是在另一组数据上(应该是更多元素的测试数据)超时了!

这两种方法是不是还有可以优化的地方呢?是不是一定要用上STL?

把几个超时的代码放在这里,留下个思考!



timus 1613. For Fans of Statistics【该题超时的代码记录】