-
注意建边、拓扑序 DP 过程,弹栈的时候最后要把当前搜到的 x x x 也弹出。
#include <bits/stdc++.h> using namespace std; const int maxn=1e4+5,maxm=1e5+5; int head1[maxn],head2[maxn],a[maxn],low[maxn],scc[maxn]/*sizeof scc*/,dfscnt,dfn[maxn],f[maxn],s[maxn],top,scccnt,cnt1,cnt2,sccnum[maxn]; struct edge{int to,nxt;}e1[maxm],e2[maxm]; bool vis[maxn]; void add1(int x,int y){e1[++cnt1]=(edge){y,head1[x]},head1[x]=cnt1;} void add2(int x,int y){e2[++cnt2]=(edge){y,head2[x]},head2[x]=cnt2;} void tarjan(int x) { low[x]=dfn[x]=++dfscnt,s[++top]=x,vis[x]=1; for(int i=head1[x];i;i=e1[i].nxt) { if(!dfn[e1[i].to]) tarjan(e1[i].to),low[x]=min(low[x],low[e1[i].to]); else if(vis[e1[i].to]) low[x]=min(low[x],dfn[e1[i].to]); } if(dfn[x]==low[x]) { sccnum[x]=++scccnt; while(s[top]!=x) sccnum[s[top]]=scccnt,vis[s[top--]]=0; vis[x]=0,top--; } } int main() { int n,m;cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1,u,v;i<=m;i++) cin>>u>>v,add1(u,v); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) { scc[sccnum[i]]+=a[i]; for(int j=head1[i];j;j=e1[j].nxt) if(sccnum[i]!=sccnum[e1[j].to]) add2(sccnum[i],sccnum[e1[j].to]); } int ans=-1; for(int ii=scccnt;ii;ii--) { f[ii]+=scc[ii],ans=max(ans,f[ii]); for(int i=head2[ii];i;i=e2[i].nxt) f[e2[i].to]=max(f[e2[i].to],f[ii]); } cout<<ans; return 0; } -
注意乘法的
lazy标记要初始化为 1 1 1。#include <bits/stdc++.h> using namespace std; #define int long long const int maxn=4e5+5; int a[maxn],s[maxn],la1[maxn],la2[maxn],m,k;//la1-multiple,la2-plus void build(int k, int l,int r) { la1[k]=1; if(l==r){s[k]=a[l]%m;return;} int mid=(l+r)/2; build(k*2,l,mid),build(k*2+1,mid+1,r),s[k]=(s[k*2]+s[k*2+1])%m; } void add(int k,int l,int r,int q1,int q2)//q1-multiple,q2-plus { s[k]=(s[k]*q1%m+(r-l+1)*q2%m)%m; la2[k]=(la2[k]*q1+q2)%m,la1[k]=(la1[k]*q1)%m; } void pushup(int k){s[k]=(s[k*2]+s[k*2+1])%m;} void pushdown(int k,int l,int r) { int mid=(l+r)/2; add(k*2,l,mid,la1[k],la2[k]),add(k*2+1,mid+1,r,la1[k],la2[k]); la1[k]=1,la2[k]=0; } void update(int k,int l,int r,int x,int y,int laz1,int laz2) { if(x<=l&&y>=r) return add(k,l,r,laz1,laz2); pushdown(k,l,r); int mid=(l+r)/2; if(x<=mid) update(k*2,l,mid,x,y,laz1,laz2); if(y>mid) update(k*2+1,mid+1,r,x,y,laz1,laz2); pushup(k); } int query(int k,int l,int r,int x,int y) { if(x<=l&&y>=r) return s[k]; int res=0,mid=(l+r)/2; pushdown(k,l,r); if(x<=mid) res=(res+query(k*2,l,mid,x,y))%m; if(y>mid) res=(res+query(k*2+1,mid+1,r,x,y))%m; return res; } signed main() { int n,q;cin>>n>>q>>m; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); for(int i=1,op,x,y;i<=q;i++) { cin>>op>>x>>y; if(op==1) cin>>k,update(1,1,n,x,y,k,0); else if(op==2) cin>>k,update(1,1,n,x,y,1,k); else cout<<query(1,1,n,x,y)<<endl; } return 0; } -
维护单调上升/下降的序列。对于一个新加入的元素,先弹出超出滑动窗口长 k k k 的队首元素,然后考虑向队尾加入元素,关键是要维护序列的单调性。双端队列存储的是序列下标。
注意数组大小。
#include <bits/stdc++.h> using namespace std; const int maxn=1e6+5; int q1[maxn],q2[maxn],a[maxn]; int main() { int n,k;cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; int h1=1,t1=0,h2=1,t2=0; for(int i=1;i<=n;i++) { while(h1<=t1&&q1[h1]+k<=i) h1++; while(h1<=t1&&a[q1[t1]]>a[i]) t1--; q1[++t1]=i; if(i>=k) cout<<a[q1[h1]]<<' '; } cout<<endl; for(int i=1;i<=n;i++) { while(h2<=t2&&q2[h2]+k<=i) h2++; while(h2<=t2&&a[q2[t2]]<a[i]) t2--; q2[++t2]=i; if(i>=k) cout<<a[q2[h2]]<<' '; } return 0; } -
注意清空根据上一步的
tot,不要每次都memset。
20231019刷题记录
算法模板:拓扑排序、线段树与滑动窗口在C++中的实现
最新推荐文章于 2025-12-07 21:20:15 发布
359

被折叠的 条评论
为什么被折叠?



