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!!!!!
}

  

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10514921.html