打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); } }
时间: 2024-10-13 23:29:09