该题的意思:按编号递增给出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+二分查询
#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?
把几个超时的代码放在这里,留下个思考!