洛谷P3527 [POI2011]MET-Meteors

题目大意:

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

(1≤n,m,k≤3*10^5,1≤p_i,a_i≤10^9)

值得一提的是这提的空间限制是(64.5MB),这样一些奇怪的树据截垢就被卡掉了

其实我们可以考虑整体二分!

我们二分时间轴,然后处理国家

构造函数(solve(tl,tr,l,r))表示在([tl,tr])场陨石雨内,还有([l,r])个国家没有确定答案

在每个(solve)内,先将([tl,mid])内的陨石全部落下,然后判断([l,r])内的国家是否满足要求,达到数目的国家分治进左侧,未达到的国家分治进右侧

考虑一个国家可能对应多个节点,其实只要用链表存在然后单点查询就好了,毕竟每一层的查询次数之和一定是(m)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) (i&-i)
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=3e5+10,inf=1e9;
	int n,m,ask,cnt;
	struct point 
	{
		int l,r,k;
	}q[N*3];
	struct node
	{
		int up,id;
	}g[N],g1[N],g2[N];
	int up[N],ret[N];
	int tr[N<<1];
	vector<int> rose[N];
	inline void add(int x,int k)
	{
		for(int i=x;i<=2*m;i+=lowbit(i)) tr[i]+=k;
	}
	inline int query(int y)
	{
		int ret=0;
		for(int i=y;i;i-=lowbit(i)) ret+=tr[i];
		return ret;
	}
	inline void solve(int tl,int tr,int l,int r)
	{
		if(l>r) return;
		if(tl==tr)
		{
			for(int i=l;i<=r;++i)
				ret[g[i].id]=tl;
			return;
		}
		int mid=(tl+tr)>>1,cnt1=0,cnt2=0,tmp;
		for(int i=tl;i<=mid;++i)
		{
			add(q[i].l,q[i].k);
			add(q[i].r+1,-q[i].k);
		}
		for(int sum,i=l;i<=r;++i)
		{
			sum=rose[g[i].id].size(),tmp=0;
			for(int k=0;k<sum;++k)
			{
				tmp+=query(rose[g[i].id][k])+query(rose[g[i].id][k]+m);
				if(tmp>g[i].up) break;
			}
			if(g[i].up<=tmp) g1[++cnt1]=g[i];
			else g[i].up-=tmp,g2[++cnt2]=g[i];
		}
		for(int i=tl;i<=mid;++i) add(q[i].l,-q[i].k),add(q[i].r+1,q[i].k);
		for(int i=1;i<=cnt1;++i) g[l+i-1]=g1[i];
		for(int i=1;i<=cnt2;++i) g[l+i+cnt1-1]=g2[i];
		solve(tl,mid,l,l+cnt1-1);
		solve(mid+1,tr,l+cnt1,r);
	}
	inline void main()
	{
		n=read(),m=read();
		for(int i=1;i<=m;++i) rose[read()].push_back(i);
		for(int i=1;i<=n;++i) g[i].up=read(),g[i].id=i;
		ask=read();
		for(int l,r,k,i=1;i<=ask;++i)
		{
			l=read(),r=read(),k=read();
			if(r<l) r+=m;
			q[++cnt]=(point){l,r,k};
		}
		solve(1,cnt+1,1,n);
		for(int i=1;i<=n;++i)
		{
			if(ret[i]>ask) puts("NIE");
			else printf("%d
",ret[i]);
		}
	}
}
signed main()
{
	red::main();
	return 0;
}
原文地址:https://www.cnblogs.com/knife-rose/p/12049117.html