luogu P3527 [POI2011]MET-Meteors

此题可以使用整体二分解决。

我们发现把所有国家收集陨石的情况都查一遍的总复杂度是固定的,那么这时候我们就可以放心的使用整体二分:

  • \(solve(l,r,x,y)\)表示\([x,y]\)这些国家,他们的答案范围在\([l,r]\)内,并设\(mid\)\([l,r]\)的中点

  • 我们先把\([l,mid]\)范围内的陨石落下,再对每个国家查询:若此国家已经收集够陨石,则他们所属答案区间为\([l,mid]\),否则更新此国家的需要陨石的数目,然后把它放进\([mid+1,r]\)

分析时间复杂度(重点):我们可以类比线段树的把我们的分支结构看成\(O(logn)\)层,然后我们发现对于国家查询,每层的复杂度相同(因为每层都会把所有国家查一遍),由于使用树状数组,所以每层均摊复杂度\(O(nlogn)\),一共\(O(log)\)层,所以总复杂度为\(O(nlog^2n)\)

代码:

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

typedef long long LL;
const int N=300009;
int n,m,L[N],R[N],A[N],k,ans[N],f;
LL c[N];
struct Edge
{
	int nxt,to;
}b[N*2];
struct Question
{
	LL need;
	int head,id;
}q[N],q_[N],Q_[N];

void Add(int from,int to)
{
	b[++f].nxt=q[from].head;
	b[f].to=to;
	q[from].head=f;
}

inline void add(int x,LL v)
{
	while(x<=m)
	{
		c[x]+=v;
		x+=x&(-x);
	}
}

inline LL getsum(int x)
{
	LL ans=0;
	while(x)
	{
		ans+=c[x];
		x-=x&(-x);
	}
	return ans;
}

inline int read()
{
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')
		c=getchar();
	while(c>='0'&&c<='9')
		x=x*10+c-'0',c=getchar();
	return x;
}

void init()
{
	n=read(),m=read();
	for (int i=1,x;i<=m;i++)
		x=read(),Add(x,i);
	for (int i=1;i<=n;i++)
		q[i].need=read(),q[i].id=i;
	k=read();
	for (int i=1;i<=k;i++)
		L[i]=read(),R[i]=read(),A[i]=read();
}

inline void Modify(int x,int y,LL v)
{
	add(x,v),add(y+1,-v);
}

inline LL Query(int x)
{
	return getsum(x);
}

inline void solve(int l,int r,int x,int y)
{
	if(l==r)
	{
		for (int i=x;i<=y;i++)
			ans[q[i].id]=l;
		return;
	}
	int mid=l+r>>1;
	for (int i=l;i<=mid;i++)
		if(L[i]<=R[i])
			Modify(L[i],R[i],A[i]);
		else
			Modify(L[i],m,A[i]),Modify(1,R[i],A[i]);
	int cnt=0,cnt_=0;
	for (int i=x;i<=y;i++)
	{
		int flag=0,j;
		for (j=q[i].head;j;j=b[j].nxt)
		{
			int v=b[j].to;
			LL Q=Query(v);
			if(q[i].need<=Q)
			{
				flag=1;
				break;
			}
			q[i].need-=Q;
		}
		if(flag)
		{
			for (int k=q[i].head;k!=j;k=b[k].nxt)
				q[i].need+=Query(b[k
				].to);
			q_[++cnt]=q[i];
		}
		else
			Q_[++cnt_]=q[i];
	}
	for (int i=l;i<=mid;i++)
		if(L[i]<=R[i])
			Modify(L[i],R[i],-A[i]);
		else
			Modify(L[i],m,-A[i]),Modify(1,R[i],-A[i]);
	int i=x;
	for (int j=1;j<=cnt;j++,i++)
		q[i]=q_[j];
	for (int j=1;j<=cnt_;i++,j++)
		q[i]=Q_[j];
	if(cnt)
		solve(l,mid,x,x+cnt-1);
	if(cnt_)
		solve(mid+1,r,x+cnt,y);
}

void work()
{
	solve(1,k+1,1,n);
	for (int i=1;i<=n;i++)
		if(ans[i]==k+1)
			puts("NIE");
		else
			printf("%d\n",ans[i]);
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-06-16 07:02  With_penguin  阅读(29)  评论(0编辑  收藏  举报