洛谷题目传送门c++
一血祭数组
向dllxl致敬!spa
算是YNOI中比较清新的吧,毕竟代码只有1.25k。code
首先咱们对着题意模拟,寻找一些思路。ip
每次选了一个最大的数后,它和它周围两个数都要减一。这样不管如何,咱们都选不到旁边那两个数,只有第一次选的那个数会对答案产生它的大小的贡献。get
因而就能够写出一个\(O(nm\log n)\)的暴力用来对拍了it
#include<bits/stdc++.h> #define LL long long #define R register int #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin)) using namespace std; const int SZ=1<<19,N=1e5+9; char buf[SZ],*ie=buf+SZ,*ip=ie-1; inline int in(){ G;while(*ip<'-')G; R x=*ip&15;G; while(*ip>'-'){x*=10;x+=*ip&15;G;} return x; } int a[N],b[N]; bool vis[N]; inline bool Cmp(R&x,R y){ return a[x]>a[y]||(a[x]==a[y]&&x<y); } int main(){ R n=in(); for(R i=1;i<=n;++i)a[i]=in(); for(R q=in();q--;){ a[in()]=in(); for(R i=1;i<=n;++i)b[i]=i; sort(b+1,b+n+1,Cmp); memset(vis+1,0,n); LL ans=0; for(R i=1;i<=n;++i){ if(vis[b[i]])continue; vis[b[i]-1]=vis[b[i]]=vis[b[i]+1]=1; ans+=a[b[i]]; } printf("%lld\n",ans); } return 0; }
进一步观察,对于一个序列中的一个极长单调区间,咱们取到了最大的、第三大的、第五大的。。。class
考虑用set维护好序列的全部极值点,相邻两个极值点所包含区间的贡献就能够经过树状数组查区间和直接算(注意分奇偶)。统计
单点修改的时候,只会影响到本身周围至多三个的极值点状态、以及左右各至多两个区间的单调性,暴力删掉原来的贡献再加新的贡献就行了。数据
统计答案时细节不少,边界问题也不少,想清楚后再动手仍是很舒服的。
时间复杂度\(O((n+m)\log n)\),由于数据范围不怎么卡(这一点也是YNOI极罕见的)因此蒟蒻直接牺牲常数来减小代码长度了qaq
#include<bits/stdc++.h> #define LL long long #define I inline #define R register int #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin)) using namespace std; typedef set<int>::iterator IT; const int SZ=1<<19,N=1e5+9; char buf[SZ],*ie=buf+SZ,*ip=ie-1; inline int in(){ G;while(*ip<'-')G; R x=*ip&15;G; while(*ip>'-'){x*=10;x+=*ip&15;G;} return x; } int n,a[N];LL ans;set<int>s; struct BIT{ LL a[N]; I void Upd(R i,R v){ for(;i<N;i+=i&-i)a[i]+=v; } I void Qry(R l,R r,LL v){ for(R i=r;i;i-=i&-i)v+=a[i]; for(R i=l;i;i-=i&-i)v-=a[i]; } }b[2]; #define ODD(O) ((*l^*O(j=l))&1) I void Calc(IT l,IT r,R op){ IT i,j;LL sum=*l&&a[*l+1]>a[*l]&&!ODD(--)&&!ODD(++)?a[*l]:0; for(i=l++;i!=r;i=l++) if(a[*l]>a[*i])b[*l&1].Qry(*i,*l,sum); else b[*i&1].Qry(*i,*l-ODD(++),sum); ans+=sum*op; } I void Chk(R x){ if((a[x]>a[x-1])!=(a[x+1]>a[x]))s.insert(x); else s.erase(x); } I void Upd(R x){ R y=in(); IT i=s.lower_bound(x),l=i,r=i; --l;if(l!=s.begin())--l; ++r;if(r==s.end()||(*i==x&&++r==s.end()))--r; Calc(l,r,-1); b[x&1].Upd(x,y-a[x]);a[x]=y; Chk(x);if(x>1)Chk(x-1);if(x<n)Chk(x+1); Calc(l,r,1); } int main(){ n=in();s.insert(0);s.insert(n+1); for(R i=1;i<=n;++i)Upd(i); for(R q=in();q;--q)Upd(in()),printf("%lld\n",ans); return 0; }