[POI2011]MET-Meteors

V.I.[POI2011]MET-Meteors

套上整体二分,然后用BIT统计区间里每个国家收到多少陨石就行了。

听说有人还有用线段树上二分之类奇怪的东西,但是真的没有必要。

时间复杂度 \(O(n\log^2n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,a[300100],q,L[300100],R[300100],V[300100],p[300100],res[300100];
bool ok[300100];
vector<int>v[300100];
ll t[300100];
void ADD(int x,int y){while(x<=m)t[x]+=y,x+=x&-x;}
ll SUM(int x){ll ret=0;while(x)ret+=t[x],x-=x&-x;return ret;}
void solve(int l,int r,int ll,int rr){
	if(l==r){for(int i=ll;i<=rr;i++)res[p[i]]=l;return;}
//	printf("[%d,%d]:",l,r);for(int i=ll;i<=rr;i++)printf("%d ",p[i]);puts("");
	if(ll>rr)return;
	int mid=(l+r)>>1;
	for(int i=l;i<=mid;i++)if(L[i]<=R[i])ADD(L[i],V[i]),ADD(R[i]+1,-V[i]);else ADD(1,V[i]),ADD(R[i]+1,-V[i]),ADD(L[i],V[i]);
	for(int i=ll;i<=rr;i++){
		long long sum=0;
		for(auto j:v[p[i]]){
			sum+=SUM(j);
			if(sum>=a[p[i]])break;
		}
//		printf("%d\n",sum);
		if(sum>=a[p[i]])ok[p[i]]=true;else ok[p[i]]=false,a[p[i]]-=sum;
	}
	for(int i=l;i<=mid;i++)if(L[i]<=R[i])ADD(L[i],-V[i]),ADD(R[i]+1,V[i]);else ADD(1,-V[i]),ADD(R[i]+1,V[i]),ADD(L[i],-V[i]);
	sort(p+ll,p+rr+1,[](int u,int v){return ok[u]>ok[v];});
	int MID=ll-1;while(MID<rr&&ok[p[MID+1]])MID++;
	for(int i=ll;i<=rr;i++)ok[p[i]]=false;
	solve(l,mid,ll,MID),solve(mid+1,r,MID+1,rr);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,x;i<=m;i++)scanf("%d",&x),v[x].push_back(i);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	scanf("%d",&q);
	for(int i=1;i<=q;i++)scanf("%d%d%d",&L[i],&R[i],&V[i]);
	q++,L[q]=1,R[q]=n,V[q]=0x3f3f3f3f;
	for(int i=1;i<=n;i++)p[i]=i;
	solve(1,q,1,n);
	for(int i=1;i<=n;i++)if(res[i]==q)puts("NIE");else printf("%d\n",res[i]);
	return 0;
}

posted @ 2021-04-06 10:52  Troverld  阅读(31)  评论(0编辑  收藏  举报