2019ICPC徐州网络赛

B. so easy

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);
        }
    }
}

G. Colorful String

M. Longest subsequence

K. Center

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<

E. XKC's basketball team

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("");
}

 

你可能感兴趣的:(acm,思维)