theme:n个数编号为1~n,两种操作:1 x:将编号为x的数置为不可得,2 x:询问x位置及其后第一个可得数的编号。1<=n,x<1e9,1<=q<1e6
solution:首先想到用线段树维护。初始时线段树每个l==r位置的值为l,1 x操作对应将x位置值置为inf,2 x 操作相当于查询区间[x,n]的最小值。由于n很大,所以要离散化。可以记录下所有操作的x值,进vector,并把x+1也作为节点,这样的话查询[x,n]就保证一定正确了
#include
#include
#include
using namespace std;
#define far(i,t,n) for(int i=t;iv;
int tree[2000020<<2];
void push_up(int rt)
{
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt]=v[l-1];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
void update(int rt,int l,int r,int pos)
{
if(l==r)
{
tree[rt]=inf;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(rt<<1,l,mid,pos);
else
update(rt<<1|1,mid+1,r,pos);
push_up(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
return tree[rt];
int mid=(l+r)>>1;
int ans=inf;
if(L<=mid)
ans=min(ans,query(rt<<1,l,mid,L,R));
if(R>mid)
ans=min(ans,query(rt<<1|1,mid+1,r,L,R));
return ans;
}
int main()
{
int n,q;
cin>>n>>q;
far(i,0,q)
{
scanf("%d%d",&a[i].z,&a[i].x);
v.push_back(a[i].x);
v.push_back(a[i].x+1);
}
sort(v.begin(),v.end());
int sz=unique(v.begin(),v.end())-v.begin();
build(1,1,sz);
far(i,0,q)
{
int pos=lower_bound(v.begin(),v.begin()+sz,a[i].x)-v.begin()+1;
if(a[i].z==1)
update(1,1,sz,pos);
else
{
int ans=query(1,1,sz,pos,sz);
printf("%d\n",ans);
}
}
}
theme:给定n个二维平面上的点,问至少添加几个点可以使得有这些点组成的图形是中心对称图形(对称中心任意)。1<=n<=1000,-1e6<=x,y<=1e6
solution:如果一个图形是中心对称图形,则对称中心是某些点对的中点。n范围较小,我们可以枚举出每个点与任意其他点的中点)(只要有一个点不同,则中点肯定不同),看哪个点是最多点对的中点。实现的话可以放在map里,再求map最大值。由于某个点自己也可能是对称中心,所以枚举i,i时对答案的贡献+1,其他情况+2表示这两个点都不需要给它加点,结果就为n-ans.注意特判n=1
#include
#include
#include
using namespace std;
#define far(i,t,n) for(int i=t;ium;
map<_a,int>::iterator it;
int main()
{
int n;
cin>>n;
far(i,0,n)
scanf("%d%d",&a[i].x,&a[i].y);
if(1==n)
{
cout<<0<second);
cout<
theme:给定长度为n的数组,给定m,对于数组中的每个数,求ai右边比ai+m大的最远(下标距离最大)的数与ai之间有几个数,没有比ai+m的大的输出-1。2<=n<=5e5,0<=m,ai<=1e9
solution:由题意只该题就是求每个元素右边>=ai+m的最远的下标。可以借助线段树每次优先往右边搜最大值。
有一种更简便的方法:将ai从小到大排序,则对于每一个ai找到>=ai+m的第一个位置,则排序后[pos,n]里所有的元素都满足要求,这时我们只需找到[pos,n]里的元素中下标的最大值即可。而用结构体记录下标和值后,排好序后用dp就可以很容易求出后缀最大值(对于下标)。注意当m=0时由于不能选到自己,此时就不要lower_bound()找pos,直接pos=i+1
#include
#include
#include
using namespace std;
#define far(i,t,n) for(int i=t;i>n>>m;
far(i,0,n)
scanf("%lld",&a[i].w),a[i].idx=i;
sort(a,a+n);
rmax[n]=-1;
for(int i=n-1;i>=0;--i)
rmax[i]=max(rmax[i+1],a[i].idx);
far(i,0,n)
{
int pos;
_a x;
x.w=a[i].w+m;
if(0==m)
pos=i+1;
else
pos=lower_bound(a,a+n,x)-a;
ans[a[i].idx]=rmax[pos]>a[i].idx?rmax[pos]-a[i].idx-1:-1;
}
printf("%d",ans[0]);
far(i,1,n)
printf(" %d",ans[i]);
puts("");
}