BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值

首先我们考虑暴力想法

对于每个国家分开讨论 二分操作次数

但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大

这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE

我们需要对浪费在这里的复杂度做一些改进

1.可持久化线段树(MLE)

每次二分一个mid之后 我们要找到mid次操作之后的版本

那么很容易想到可持久化线段树

这样每次二分到一个mid可以O(logm)得到值 时间复杂度O(klogm+nlogklogm)

残念的是我MLE了- - 本来以为写了标记永久化的线段树能省掉不少空间的- - 结果- -

内存池就算开了1500W也不够用 真是卡成狗- -

2.整体二分

不能从k下手,我们就要从n下手

二分Solve(x,y,S)表示答案落在[x,y]区间内的国家集合为S

将当前的修改调整至mid,将S集合分为两部分:答案落在[l,mid]的S1和[mid+1,r]的S2

对这两部分继续分治 直到x==y为止 统计答案 退出

时间复杂度O(nlogklogm) 此外注意30W*30W*10E会爆long long 所以我开成了double。。。

代码(整体二分):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
struct Segtree{
	Segtree *ls,*rs;
	double val;
	void* operator new (size_t)
	{
		static Segtree mempool[M<<1],*C=mempool;
		return C++;
	}
	void Build_Tree(int x,int y)
	{
		int mid=x+y>>1;
		if(x==y)
			return ;
		ls=new Segtree;
		rs=new Segtree;
		ls->Build_Tree(x,mid);
		rs->Build_Tree(mid+1,y);
	}
	void Modify(int x,int y,int l,int r,int val)
	{
		int mid=x+y>>1;
		if(x==l&&y==r)
		{
			this->val+=val;
			return ;
		}
		if(r<=mid) ls->Modify(x,mid,l,r,val);
		else if(l>mid) rs->Modify(mid+1,y,l,r,val);
		else ls->Modify(x,mid,l,mid,val),rs->Modify(mid+1,y,mid+1,r,val);
	}
	double Get_Ans(int x,int y,int pos)
	{
		int mid=x+y>>1;
		if(x==y)
			return val;
		if(pos<=mid)
			return val+ls->Get_Ans(x,mid,pos);
		else
			return val+rs->Get_Ans(mid+1,y,pos);
	}
}tree;
struct abcd{
	int pos,next;
}table[M];
struct modification{
	int l,r,p;
}modifications[M];
int head[M],tot;
int n,m,k,now;
int a[M],q[M],ans[M];
void Add(int x,int y)
{
	table[++tot].pos=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void Holistic_Bisection(int x,int y,int l,int r)
{
	static int nq[M];
	int i,mid=x+y>>1;
	if(l>r) return ;
	if(x==y)
	{
		for(i=l;i<=r;i++)
			ans[q[i]]=mid;
		return ;
	}
	while(now<mid)
	{
		++now;
		if(modifications[now].l<=modifications[now].r)
			tree.Modify(1,m,modifications[now].l,modifications[now].r,modifications[now].p);
		else
			tree.Modify(1,m,1,modifications[now].r,modifications[now].p),
			tree.Modify(1,m,modifications[now].l,m,modifications[now].p);
	}
	while(now>mid)
	{
		if(modifications[now].l<=modifications[now].r)
			tree.Modify(1,m,modifications[now].l,modifications[now].r,-modifications[now].p);
		else
			tree.Modify(1,m,1,modifications[now].r,-modifications[now].p),
			tree.Modify(1,m,modifications[now].l,m,-modifications[now].p);
		--now;
	}
	int _l=l,_r=r;
	for(int j=l;j<=r;j++)
	{
		double temp=0;
		for(i=head[q[j]];i;i=table[i].next)
		{
			temp+=tree.Get_Ans(1,m,table[i].pos);
			if(temp>=1000000000)
				temp=1000000000;
		}
		if(temp>=a[q[j]])
			nq[_l++]=q[j];
		else nq[_r--]=q[j];
	}
	memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1) );
	Holistic_Bisection(x,mid,l,_l-1);
	Holistic_Bisection(mid+1,y,_r+1,r);
}
int main()
{
	int i,x;
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&x);
		Add(x,i);
	}
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	tree.Build_Tree(1,m);
	cin>>k;
	for(i=1;i<=k;i++)
		scanf("%d%d%d",&modifications[i].l,&modifications[i].r,&modifications[i].p);
	for(i=1;i<=n;i++)
		q[i]=i;
	Holistic_Bisection(1,k+1,1,n);
	for(i=1;i<=n;i++)
	{
		if(ans[i]<=k) printf("%d\n",ans[i]);
		else puts("NIE");
	}
	return 0;
}

代码(可持久化线段树):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
typedef long long ll;

struct Segtree{
	Segtree *ls,*rs;
	int val;
	void* operator new (size_t,Segtree *_,Segtree *__,ll ___)
	{
		static Segtree mempool[17500000],*C=mempool;
		C->ls=_;
		C->rs=__;
		C->val=___;
		if(C->val>=1000000000)
			C->val=1000000000;
		return C++;
	}
}*tree[M];
struct abcd{
	int pos,next;
}table[M];
int head[M],tot;
int n,m,k,a[M];
Segtree* Modify(Segtree *p,int x,int y,int l,int r,ll val)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
		return new (p->ls,p->rs,p->val+val) Segtree;
	if(r<=mid)
		return new (Modify(p->ls,x,mid,l,r,val),p->rs,p->val) Segtree;
	if(l>mid) return new (p->ls,Modify(p->rs,mid+1,y,l,r,val),p->val) Segtree;
	return new (Modify(p->ls,x,mid,l,mid,val),Modify(p->rs,mid+1,y,mid+1,r,val),p->val) Segtree;
}
Segtree* Modify(Segtree *p,int x,int y,int l,int r,ll val,bool)
{
	int mid=x+y>>1;
	if(l>mid) return new (new(p->ls->ls,p->ls->rs,p->ls->val+val)Segtree,Modify(p->rs,mid+1,y,l,r,val,true),p->val) Segtree;
	if(r<=mid) return new (Modify(p->ls,x,mid,l,r,val,true),new(p->rs->ls,p->rs->rs,p->rs->val+val)Segtree,p->val) Segtree;
	return new (Modify(p->ls,x,mid,x,l,val),Modify(p->rs,mid+1,y,r,y,val),p->val) Segtree;
}
ll Get_Ans(Segtree *p,int x,int y,int pos)
{
	int mid=x+y>>1;
	if(p==tree[0]) return 0;
	if(x==y) return p->val;
	if(pos<=mid) return p->val+Get_Ans(p->ls,x,mid,pos);
	else return p->val+Get_Ans(p->rs,mid+1,y,pos); 
}
void Initialize()
{
	tree[0]=new (0x0,0x0,0) Segtree;
	tree[0]->ls=tree[0]->rs=tree[0];
}
void Add(int x,int y)
{
	table[++tot].pos=y;
	table[tot].next=head[x];
	head[x]=tot;
}
int Bisection(int x)
{
	int i,l=0,r=k+1;
	while(l+1<r)
	{
		int mid=l+r>>1;
		long long now=0;
		for(i=head[x];i;i=table[i].next)
			now+=Get_Ans(tree[mid],1,m,table[i].pos);
		if(now>=a[x])
			r=mid;
		else
			l=mid;
	}
	long long now=0;
	for(i=head[x];i;i=table[i].next)
		now+=Get_Ans(tree[l],1,m,table[i].pos);
	return now>=a[x]?l:r;
}
int main()
{
	int i,x,y,z;
	Initialize();
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&x);
		Add(x,i);
	}
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	cin>>k;
	for(i=1;i<=k;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		if(x<=y) tree[i]=Modify(tree[i-1],1,m,x,y,z);
		else tree[i]=Modify(tree[i-1],1,m,y,x,z,true);
	}
	for(i=1;i<=n;i++)
	{
		int temp=Bisection(i);
		if(temp==k+1) puts("NIE");
		else printf("%d\n",temp);
	}
	return 0;
}


你可能感兴趣的:(线段树,bzoj,整体二分,可持久化数据结构,BZOJ2527)