哎,感觉这题出的很常规,也很简单,可比赛的时候就是想不起来......
题意:输入n,q表示右1到n这n个数按从小到大的顺序排列,初始状态这n个数都是有效值,然后q次操作,1 x 表示将x置为无效值,2 x表示询问x到n中第一个有效值为多少,输出这个有效值。
并查集就行了......
AC代码:747ms(unordered_map 确实比 map 快不少,map 要1723ms,unordered_map 只要747ms)
#include<bits/stdc++.h>
#include <tr1/unordered_map>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
int n;
//map<int,int> fa;
tr1::unordered_map<int, int>fa;
int findfa(int x)
{
if(fa.count(x)==0)
return x;
return fa[x]=findfa(fa[x]);
}
int main()
{
int q;
scanf("%d%d",&n,&q);
int z,x;
while(q--)
{
scanf("%d%d",&z,&x);
if(z==1)
fa[x]=findfa(x+1);
else
{
int ans=findfa(x);
if(ans>n)
ans=-1;
printf("%d\n",ans);
}
}
return 0;
}
题意:给定一个序列,从每一个数后面比它大至少 m 的数中求出与它之间最大的距离。 如果没有则为 -1。
对于每一个数,利用二分的方法求他右边大于等于ai+m的数的最后一个值。
关键在于怎么二分呢?
利用线段树或ST表在 log n 时间内求区间最大值,看这个区间的最大值是不是比ai+m大。
AC代码:747ms
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=100010;
using namespace std;
int n,a[500010];
int f[500010][21];
int ans[500010];
void ST_prework()
{
for(int i=1;i<=n;i++)
f[i][0]=a[i];
int t=log(n)/log(2)+1;
for(int j=1;j<t;j++)
for(int i=1;i<=n-(1<<j)+1;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int ST_query(int l,int r) //返回a[l]到a[r]中的最大值
{
int k=log(r-l+1)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
bool ok(int l,int r,int x)
{
if(ST_query(l,r)>=x)
return true;
return false;
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
ST_prework();
for(int i=1;i<=n;i++)
{
int p=-1;
int l=i,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(ok(mid,r,a[i]+m))
l=mid+1,p=max(p,mid);
else
r=mid-1;
}
if(a[l]>=a[i]+m)
p=max(p,l);
if(p==-1)
ans[i]=-1;
else
ans[i]=p-i-1;
}
for(int i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",ans[i]);
else
printf("%d",ans[i]);
}
return 0;
}