首页 > 代码库 > 洛谷2017-2月月赛

洛谷2017-2月月赛

打CF前随便打打,看了一眼只会做签到题,还挂了一次,95/400。

 

A.富金森林公园

题目大意:给一个长度为n的数列,支持两种操作:1.修改一个数的值;2.给出一个k,问有多少段数大等于k。(N<=200,000)

思路:求出大等k的数的个数减去相邻且都大等k的数字对数就是答案,同时大等两个数必然也大等他们中的较大值,所以用权值线段树分别维护各个数字和相邻的数的最大值就可以了。复杂度O(nlogn)。(一开始我写修改时,查他位置上前一个数写成前一个操作位置上的数,挂的惨烈……)

#include<cstdio>
#include<algorithm>
using namespace std;
char B[1<<26],*S=B,C;int X;
inline int read()
{
    while((C=*S++)<0||C>9);
    for(X=C-0;(C=*S++)>=0&&C<=9;)X=(X<<3)+(X<<1)+C-0;
    return X;
}
#define MN 200000
#define MC 400000
int a[MN+5],c[MC+5],cn,x[MN+5],y[MN+5],z[MN+5];
int p1[MN+5],p2[MN+5],s1[MC+5],s2[MC+5];
void add(int*s,int x,int z){for(;x<=MC;x+=x&-x)s[x]+=z;}
int sum(int*s,int x){int r=0;for(;x;x-=x&-x)r+=s[x];return r;}
#define find(x) (lower_bound(c+1,c+cn+1,x)-c)
#define find2(x) (upper_bound(c+1,c+cn+1,x)-c)
int main()
{
    fread(B,1,1<<26,stdin);
    int n,m,i,j;
    cn=n=read();m=read();
    for(i=1;i<=n;++i)a[i]=c[i]=-read();
    for(i=1;i<=m;++i)
    {
        x[i]=read();y[i]=read();
        if(x[i]>1)c[++cn]=z[i]=-read();
    }
    sort(c+1,c+cn+1);
    for(i=1,j=0;i<=cn;++i)if(c[i]!=c[j])c[++j]=c[i];cn=j;
    for(i=1;i<=n;++i)add(s1,p1[i]=find(a[i]),1);
    for(i=1;i<n;++i)add(s2,p2[i]=find(max(a[i],a[i+1])),1);
    for(i=1;i<=m;++i)
        if(x[i]<2)j=find2(-y[i])-1,printf("%d\n",sum(s1,j)-sum(s2,j));
        else
        {
            add(s1,p1[y[i]],-1);add(s1,p1[y[i]]=find(a[y[i]]=z[i]),1);
            if(y[i]>1)add(s2,p2[y[i]-1],-1),add(s2,p2[y[i]-1]=find(max(a[y[i]-1],a[y[i]])),1);
            if(y[i]<n)add(s2,p2[y[i]],-1),add(s2,p2[y[i]]=find(max(a[y[i]],a[y[i]+1])),1);
        }
}

 

洛谷2017-2月月赛