您的位置:首页 > 其它

POJ 3145Harmony Forever(线段树更新+分情况处理数据+区间极值查询+好题)

2017-08-18 20:34 495 查看
We believe that every inhabitant of this universe eventually will find a way to live together in harmony and peace; that trust, patience, kindness and loyalty will exist between every living being of this earth; people will find a way to appreciate and cooperate
with each other instead of continuous bickering, arguing and fighting. Harmony — the stage of society so many people dream of and yet it seems so far away from now…

Fortunately, the method of unlocking the key to true Harmony is just discovered by a group of philosophers. It is recorded on a strange meteorite which has just hit the earth. You need to decipher the true meaning behind those seemingly random symbols… More
precisely, you are to write a program which will support the following two kinds of operation on an initially empty set S:

B X: Add number X to set S. The Kth command in the form of B X always happens at time K, and number X does not belong to set S before this operation.
A Y : Of all the numbers in set S currently, find the one which has the minimum remainder when divided by Y. In case a tie occurs, you should choose the one which appeared latest in the input. Report the time when this element
is inserted.
It is said that if the answer can be given in the minimum possible time, true Harmony can be achieved by human races. You task is to write a program to help us.

Input

There are multiple test cases in the input file. Each test case starts with one integer T where 1 ≤ T ≤ 40000. The following T lines each describe an operation, either in the form of “B X” or “A Y ” where 1 ≤ X ≤
500 000, 1 ≤ Y ≤ 1 000 000.

T = 0 indicates the end of input file and should not be processed by your program.

Output

Print the result of each test case in the format as indicated in the sample output. For every line in the form of “A Y”, you should output one number, the requested number, on a new line; output 
-1
 if no such number can be found. Separate
the results of two successive inputs with one single blank line.

Sample Input
5
B 1
A 5
B 10
A 5
A 40
2
B 1
A 2
0


Sample Output
Case 1:
1
2
1

Case 2:
1


题解:

做了我三个小时的题。。。一开始没啥思路,后来看了下题解说是分情况讨论。。然后就自己琢磨了一下午。。。先是RE了四五次,再TLE了四五次,然后WA了四五次。。终于做出来了,感觉又收获了一种解题思维

题意:

开局一个空集合,数字全靠用'B'来加,一交就是WA。。。额跑题了,B操作就就是将集合加入一个值为v的数字(该数字独一无二),A操作加上V就是在集合中找一个%v最小的数字的在集合中的位置,如果相同就输出最右边那个

思路:

这题要分两种情况处理,当‘A’操作时,v的值很小,这时我们直接暴力用数组来求该位置,注意要从后往前扫不然会TLE(如果用线段树求就不划算会更慢,之后会说)

如果v值比较大的时候,这时线段树的优越性就体现出来了,我们用一颗线段树,初始所有区间最小值置为最大,如果插入了一个值v,那么我们就在线段树位置v处插入一个值v,当我们询问一个值v的时候,我们就在[1,v-1][v,2*v-1],[2v,3*v-1]。。。处寻找每个区间的最小值,如果值相同,比较位置,保存位置在后面的数为询问的数

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<string>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<deque>
using namespace std;
#define lson k*2
#define rson k*2+1
#define M (t[k].l+t[k].r)/2
#define INF 1008611111
#define ll long long
#define eps 1e-15
struct node
{
int l,r;
int minn;
}t[500005*4];
void Build(int l,int r,int k)
{
t[k].l=l;
t[k].r=r;
t[k].minn=INF;
if(l==r)
return;
int mid=M;
Build(l,mid,lson);
Build(mid+1,r,rson);
}
void pushup(int k)
{
t[k].minn=min(t[lson].minn,t[rson].minn);
}
void update(int pos,int k)//线段树日常更新
{
if(t[k].l==t[k].r)
{
t[k].minn=pos;
return;
}
int mid=M;
if(pos<=mid)
update(pos,lson);
else
update(pos,rson);
pushup(k);
}
int query(int l,int r,int k)//线段树日常询问
{
if(t[k].minn==INF)
return INF;
if(l==t[k].l&&t[k].r==r)
{
return t[k].minn;
}
int mid=M;
if(r<=mid)
return query(l,r,lson);
else if(l>mid)
return query(l,r,rson);
else
{
return min(query(l,mid,lson),query(mid+1,r,rson));
}
}
int len,n,maxx,minn;
int a[40005];//存插入位置i的数为多少
int vis[500005];//存数字i插入的位置
int main()
{
int i,j,m,cas=1,x,q;
char s[10];
while(scanf("%d",&m)!=EOF&&m)
{
if(cas!=1)
printf("\n");
printf("Case %d:\n",cas);
cas++;
len=0;
Build(0,500000,1);
minn=INF;
maxx=0;
while(m--)
{
scanf("%s%d",s,&x);
if(s[0]=='B')
{
a[len]=x;
update(x,1);
len++;
if(maxx<x)
maxx=x;
if(minn>x)
minn=x;
vis[x]=len;//记录插入位置
}
else
{
if(len==0)
{
printf("-1\n");
continue;
}
if(x<=5000)//这个值按照感觉定
{
int d,v=INF;
int pos;
for(i=len-1;i>=0;i--)//从后往前找更有效率
{
if(a[i]%x<v)
{
v=a[i]%x;
d=a[i];
if(v==0)//如果已经是0了不可能有更小的了就退出,这个很重要
break;
}
}
printf("%d\n",vis[d]);
}
else
{
int v=INF,d,i,en,q,to;
if(x>maxx)//如果x大于插入的最大值就直接输出插入的最小值
d=minn;
else
{
for(i=0;i<=maxx;i+=x)//询问各个区间
{
to=i+x-1;
if(to>maxx)//防止越界
to=maxx;
q=query(i,to,1);
if(q!=INF&&v>q%x)
{
v=q%x;
d=q;
}
else if(q!=INF&&v==q%x)
{
if(vis[d]<vis[q])//保存位置在后面的
d=q;
}
}
}
printf("%d\n",vis[d]);
}
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐