P3527 [POI2011]MET-Meteors

P3527 [POI2011]MET-Meteors

题意

给定一段1-m的区间,n个国家,每个位置属于一个国家
每个国家有目标的权值
有k次操作,对于每次操作

  1. l<=r l-r区间内的位置上的权值+v
  2. l>r l-m,1-r区间内的位置上的权值+v
  3. 问最少几次操作,后国家所有地区的权值和达到目标

达不到输出NIE

\(1\le n,m,k\le 3\cdot10^5\)

\(1\le p_i,a_i\le 10^9\)

正文

直接主席树动态记录每次操作后的区间的状态
对于每个国家单独二分最小操作次数
时间复杂度\(o(nlognlogn)\)

ps:不做处理n*m*vll 题目空间限制60MB的话就MLE 主席树不优化空间要开n*logn*4

考虑整体二分
类似与cdq分治的思想
时间 修改查询一起分治

直接用树状数组维护修改操作
时间复杂度\(o(nlognlogn)\)

将区间修改操作拆分为左右端点,左加右减
通过前缀和&修改位置判定统计
初始按修改位置排序,分治过程中维护区间内位置有序(同cdq分治维护内部有序)
按每个位置单独计算贡献,按国家是否达到目标 区分该分到左或右区间
时间复杂度\(o(nlogn)\)

主席树code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
	ll s=0,r=1;
	char c=C;
	for(;c<0||c>9;c=C) if(c==-3) r=-1;
	for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
	return s*r;
}
#define pb push_back
const int N=3e5+10,inf=1e9+7;
int n,m,k,top,tmpv;
ll a[N];
int rt[N];
vector<int>b[N];
struct xin{
	int l,r;
	ll sum;
}tr[N*55];
inline void build(int &x,int l,int r)
{
	x=++top;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(tr[x].l,l,mid);build(tr[x].r,mid+1,r);
}
inline int add(int x,int l,int r,int ql,int qr,int qv)
{
	int xx=++top;tr[xx]=tr[x];
	if(ql<=l&&r<=qr)
	{
		tr[xx].sum+=qv;
		if(tr[xx].sum>=inf) tr[xx].sum=inf;
		return xx;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) tr[xx].l=add(tr[x].l,l,mid,ql,qr,qv);
	if(mid+1<=qr) tr[xx].r=add(tr[x].r,mid+1,r,ql,qr,qv);
	return xx;
}
inline void ask(int x,int l,int r,int qw)
{
	tmpv+=tr[x].sum;
	if(tmpv>=inf) tmpv=inf; 
	if(l==r) return;
	int mid=(l+r)>>1;
	if(qw<=mid) ask(tr[x].l,l,mid,qw);
	if(mid+1<=qw) ask(tr[x].r,mid+1,r,qw);
}
inline int pd(int w,int wk)
{
	tmpv=0;
	for(int i=0,edi=b[w].size();i<edi;i++)
	{
		int u=b[w][i];
		
		ask(rt[wk],1,m,u);
	}
	return tmpv>=a[w];
}
inline void two(int w)
{
	int l=1,r=k;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(pd(w,mid)) r=mid;
		else l=mid+1;
	}
	if(pd(w,r)) printf("%d\n",r);
	else puts("NIE"); 
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++) b[read()].pb(i);
	for(int i=1;i<=n;i++) a[i]=read();
	k=read();build(rt[0],1,m);
	for(int i=1;i<=k;i++)
	{
		int l=read(),r=read(),v=read();
		if(l<=r)
		{
			rt[i]=add(rt[i-1],1,m,l,r,v);
		}
		if(l>r)
		{
			int tmprt=add(rt[i-1],1,m,l,m,v);
			rt[i]=add(tmprt,1,m,1,r,v);
		}
	}
	for(int i=1;i<=n;i++) two(i);
	return 0;
}

整体二分拆分区间code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
	ll s=0,r=1;
	char c=C;
	for(;c<0||c>9;c=C) if(c==-3) r=-1;
	for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
	return s*r;
}
const int N=3e5+10,inf=1e9+7;
int n,m,k,topq;
int g[N],a[N],akw[N],ans[N];
int tmpakw[N];
ll sum[N],re[N];
struct xin{
	int w,t,v;
	friend bool operator<(const xin &a,const xin &b)
	{
		return a.w<b.w;
	}
}q[N<<2],tmpq[N<<2];
inline void cdq(int tl,int tr,int akl,int akr,int ql,int qr)
{
	if(tl==tr)
	{
		for(int i=akl;i<=akr;i++) ans[g[akw[i]]]=tl;
		return;
	}
	int midt=(tl+tr)>>1;
	int tmpql=ql,tmpqr=qr;
	copy(q+ql,q+1+qr,tmpq+ql);
	for(int i=ql;i<=qr;i++)
	{
		if(tmpq[i].t<=midt) q[tmpql++]=tmpq[i];
		else q[tmpqr--]=tmpq[i];
	}
	reverse(q+tmpqr+1,q+1+qr);
	int tmpakl=akl,tmpakr=akr;
	copy(akw+akl,akw+1+akr,tmpakw+akl);
	for(int i=akl;i<=akr;i++) 
	{
		int u=g[tmpakw[i]];
		re[u]=sum[u];
	}
	ll tmpsum=0;
	for(int i=akl,j=ql;i<=akr;i++) 
	{
		int w=tmpakw[i];int u=g[w];
		while(j<=tmpqr&&q[j].w<=w)
		{
			tmpsum+=q[j].v;
			j++;
		}
		sum[u]+=tmpsum;
		if(sum[u]>=inf) sum[u]=inf;
	}
	for(int i=akl;i<=akr;i++) 
	{
		int w=tmpakw[i];int u=g[w];
		if(sum[u]>=a[u])
		{
			akw[tmpakl++]=w;
		}
		else
		{
			akw[tmpakr--]=w;
			re[u]=-1;
		}
	}
	for(int i=akl;i<=akr;i++) 
	{
		int w=tmpakw[i];int u=g[w];
		if(re[u]!=-1) sum[u]=re[u];
	}
	reverse(akw+tmpakr+1,akw+1+akr);
	cdq(tl,midt,akl,tmpakr,ql,tmpqr);
	cdq(midt+1,tr,tmpakr+1,akr,tmpqr+1,qr);
}
int main()
{
	n=read(),m=read();
	for(int i=0;i<=m;i++) akw[i]=i;
	for(int i=1;i<=m;i++) g[i]=read();
	for(int i=1;i<=n;i++) a[i]=read();
	k=read();
	for(int i=1;i<=n;i++) ans[i]=k+1;
	for(int i=1;i<=k;i++)
	{
		int l=read(),r=read(),v=read();
		if(l<=r)
		{
			q[++topq]=(xin){l,i,v};
			q[++topq]=(xin){r+1,i,-v};
		}
		else
		{
			q[++topq]=(xin){l,i,v};
			q[++topq]=(xin){m+1,i,-v};
			q[++topq]=(xin){1,i,v};
			q[++topq]=(xin){r+1,i,-v};
		}
	}
	sort(q+1,q+1+topq);
	cdq(0,k+1,1,m,1,topq);
	for(int i=1;i<=n;i++)
	{
		if(ans[i]==k+1) puts("NIE");
		else printf("%d\n",ans[i]);
	}
	return 0;
}
posted @ 2022-11-18 12:41  1436177712  阅读(27)  评论(0编辑  收藏  举报