D:从后往前考虑每个人,显然如果能移到最后一个人后方就应该立即移动,否则移不移没什么影响。链表暴力模拟这个过程即可。容易发现复杂度是线性的(判断两人间是否有边可能需要带log)。当然事实上根本不需要链表,直接检查其对后方未删除点的出度之和即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; #define ll long long #define N 300010 #define M 500010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],p[N],t,nxt[N],pre[N],degree[N],ans; map<int,int> f[N]; void del(int k) { nxt[pre[k]]=nxt[k]; pre[nxt[k]]=pre[k]; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); f[x][y]=1;degree[x]++; } for (int i=0;i<n;i++) nxt[i]=i+1; for (int i=1;i<=n;i++) pre[i]=i-1; for (int i=n-1;i>=1;i--) { int x=a[i]; if (f[x][a[n]]) { if (n-i-ans>degree[x]) continue; int u=i; while (u!=n) { if (!f[x][a[nxt[u]]]) break; u=nxt[u]; } if (u==n) { ans++; del(i); } } } cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
E:分块,每块维护第一个数和块的总和。注意到每次修改影响的是一段连续区间,于是根据块的第一个数暴力找到最后一个影响块,对其之前的块更新第一个数与总和,修改点所在的块和最后一个块暴力重构。查询时暴力重构端点所在的块就完了。当然也可以线段树,做法类似。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,q,b[N],block,num,pos[N],L[N],R[N]; ll S[N],SS[N],sum[N],a[N],first[N],val[N]; void update(int k) { a[L[k]]=first[k];sum[k]=a[L[k]]; for (int i=L[k]+1;i<=R[k];i++) a[i]=max(a[i],a[i-1]+b[i-1]),sum[k]+=a[i]; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read();block=sqrt(n);num=(n-1)/block+1; for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<n;i++) b[i]=read(); for (int i=1;i<n;i++) S[i]=S[i-1]+b[i]; for (int i=1;i<=num;i++) { L[i]=R[i-1]+1;R[i]=min(n,L[i]+block-1); for (int j=L[i];j<=R[i];j++) { if (j==L[i]) SS[j]=0; else SS[j]=SS[j-1]+b[j-1]; val[i]+=SS[j]; pos[j]=i,sum[i]+=a[j]; } first[i]=a[L[i]]; } q=read(); while (q--) { char c=getchar(); while (c!='+'&&c!='s') c=getchar(); if (c=='+') { int p=read(),x=read(); update(pos[p]); a[p]+=x;if (p==L[pos[p]]) first[pos[p]]+=x; update(pos[p]); int u=num+1; for (int i=pos[p]+1;i<=num;i++) if (first[i]>a[p]+S[L[i]-1]-S[p-1]) {u=i;break;} u--; for (int i=pos[p]+1;i<u;i++) first[i]=a[p]+S[L[i]-1]-S[p-1], sum[i]=1ll*first[i]*(R[i]-L[i]+1)+val[i]; if (u!=pos[p]) { first[u]=a[p]+S[L[u]-1]-S[p-1]; update(u); } } else { int l=read(),r=read(); if (pos[l]==pos[r]) { update(pos[l]);ll ans=0; for (int i=l;i<=r;i++) ans+=a[i]; printf("%I64d ",ans); } else { update(pos[l]),update(pos[r]);ll ans=0; for (int i=l;i<=R[pos[l]];i++) ans+=a[i]; for (int i=L[pos[r]];i<=r;i++) ans+=a[i]; for (int i=pos[l]+1;i<pos[r];i++) ans+=sum[i]; printf("%I64d ",ans); } } } return 0; //NOTICE LONG LONG!!!!! }