【SPOJ METEORS】 Meteors

http://www.spoj.com/problems/METEORS/ (题目链接)

题意

  一个星球上有$m$个空间站排列在一个环形轨道上,每个空间站仅属于一个国家。总共有$K$场流星雨,这些流星雨降落在区间$[l,r]$的空间站并带来$w$的陨石。每个国家想要收获$p_i$的陨石,问每个国家最少在第几场流星雨过后收集到的陨石达到要求。

Solution

  整体二分很明显,一开始复杂度算错了T_T。

细节

  本机7s,SPOJ竟然跑过去了w(゚Д゚)w。听说会爆LL

代码

// spojMETEORS
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define ULL unsigned long long
#define inf 2147483600
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;
inline int gi() {
	int x=0,f=1;char ch=getchar();
	while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int maxn=300010;
int n,m,K,cnt,a[maxn],ans[maxn],head[maxn];
struct edge {int to,next;}e[maxn];
struct data {int w,id;}p[maxn],lp[maxn],rp[maxn];
struct node {int l,r;ULL s,tag;}tr[maxn<<2];
struct mete {int l,r,w;}q[maxn];

namespace Segtree {
	void build(int k,int s,int t) {
		tr[k].l=s;tr[k].r=t;
		if (s==t) return;
		int mid=(s+t)>>1;
		build(k<<1,s,mid);
		build(k<<1|1,mid+1,t);
	}
	void modify(int k,int s,int t,LL val) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		if (l==s && r==t) {tr[k].s+=val*(r-l+1);tr[k].tag+=val;return;}
		if (t<=mid) modify(k<<1,s,t,val);
		else if (s>mid) modify(k<<1|1,s,t,val);
		else modify(k<<1,s,mid,val),modify(k<<1|1,mid+1,t,val);
		tr[k].s=tr[k<<1].s+tr[k<<1|1].s;
	}
	ULL query(int k,int p) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		if (l==r) return tr[k].s;
		if (p<=mid) return query(k<<1,p)+tr[k].tag;
		else return query(k<<1|1,p)+tr[k].tag;
	}
}
using namespace Segtree;

void link(int u,int v) {
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
}
void solve(int ql,int qr,int l,int r) {
	if (ql>qr) return;
	int mid=(ql+qr)>>1,l1=0,l2=0;
	for (int i=ql;i<=mid;i++) {
		if (q[i].l>q[i].r) modify(1,q[i].l,m,q[i].w),modify(1,1,q[i].r,q[i].w);
		else modify(1,q[i].l,q[i].r,q[i].w);
	}
	for (int i=l;i<=r;i++) {
		ULL sum=0;
		for (int j=head[p[i].id];j;j=e[j].next) sum+=query(1,e[j].to);
		if (p[i].w<=sum) lp[++l1]=p[i],ans[p[i].id]=mid;
		else rp[++l2]=p[i];
	}
	for (int i=1;i<=l1;i++) p[l+i-1]=lp[i];
	for (int i=1;i<=l2;i++) p[r-i+1]=rp[i];
	if (l+l1<=r) solve(mid+1,qr,l+l1,r);
	for (int i=ql;i<=mid;i++) {
		if (q[i].l>q[i].r) modify(1,q[i].l,m,-q[i].w),modify(1,1,q[i].r,-q[i].w);
		else modify(1,q[i].l,q[i].r,-q[i].w);
	}
	if (l<=r-l2) solve(ql,mid-1,l,r-l2);
}
int main() {
	n=gi(),m=gi();
	for (int i=1;i<=m;i++) a[i]=gi();
	for (int i=1;i<=m;i++) link(a[i],i);
	for (int i=1;i<=n;i++) p[i].w=gi(),p[i].id=i;
	K=gi();
	for (int i=1;i<=K;i++) q[i].l=gi(),q[i].r=gi(),q[i].w=gi();
	build(1,1,m);
	solve(1,K,1,n);
	for (int i=1;i<=n;i++) {
		if (!ans[i]) puts("NIE");
		else printf("%d\n",ans[i]);
	}
	return 0;
}

 

转载于:https://www.cnblogs.com/MashiroSky/p/6522756.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值