Codeforces Round #546 Div. 2
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\n",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\n",ans);
}
}
}
return 0;
//NOTICE LONG LONG!!!!!
}

浙公网安备 33010602011771号