【题解】P3527 [POI 2011] MET-Meteors

分治或者叫整体二分。

对于分治的每一次将国家向左或向右分成两部分,因为要求的是个最小前缀,所有左半部分的陨石不满足就将这个国家分到有半部分,满足就说明在左半部分的某处。

#include <bits/stdc++.h>
#define ll long long
#define int ll
#define ls a[p].l
#define rs a[p].r 
#define re register 
#define pb push_back
#define pir pair<int,int>
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
using namespace std;
const int N=3e5+10;
const int M=8e6+10;
const int mod=1e9+7;
mt19937 rnd(251);

int n,m;
int ans[N];
int lim=1e18;

vector<int> pos[N];
int p[N];

struct BIT{
	int lb(int x){
		return (x&-x);
	}
	int t[N];
	void set(int x){
		for(;x<=m;x+=lb(x)) t[x]=0;
	}
	void update(int x,int k){
		for(;x<=m;x+=lb(x)) t[x]+=k,t[x]=min(t[x],lim);
	}	
	void add(int l,int r,int x){
		update(l,x);
		update(r+1,-x);
	}
	int query(int x){
		int sum=0;
		for(;x;x-=lb(x)) sum+=t[x],sum=min(sum,lim);
		return sum;
	}

} bit;

void solve(vector<int> &country,auto &range,int L,int R){
	if(L==R){
		for(int x:country){
			ans[x]=L;
		}
		return;
	}
	if(country.size()==0) return;
	int mid=(L+R)>>1;
	vector<tuple<int,int,int,int>> lrange,rrange;

	for(auto &[l,r,x,i]:range){
		if(i>mid){
			rrange.push_back({l,r,x,i});
			continue;
		}
		bit.add(l,r,x);
		lrange.push_back({l,r,x,i});
	}
	vector<int> countryl,countryr;
	for(auto &x:country){
		int sum=0;
		for(int y:pos[x]) sum+=bit.query(y),sum=min(sum,lim);
		if(sum>=p[x]) countryl.push_back(x);
		else countryr.push_back(x),p[x]-=sum;
	}
	for(auto &[l,r,x,i]:lrange){
		bit.set(l);
		bit.set(r+1);
	}
	
	solve(countryl,lrange,L,mid);
	solve(countryr,rrange,mid+1,R);
}


signed main(){
	// freopen("a.in","r",stdin);
	// freopen("a.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(nullptr);   
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x;
		cin>>x;
		pos[x].push_back(i);
	}
	for(int i=1;i<=n;i++){
		cin>>p[i];
	}
	int k;
	cin>>k;
	vector<tuple<int,int,int,int>> range;
	for(int i=1;i<=k;i++){
		int l,r,x;
		cin>>l>>r>>x;
		if(l<=r){
			range.push_back({l,r,x,i});
		}
		else{
			range.push_back({l,m,x,i});
			range.push_back({1,r,x,i});
		}
	}
	vector<int> country(n);
	iota(country.begin(),country.end(),1);

	solve(country,range,0,k+1);

	for(int i=1;i<=n;i++){
		if(ans[i]<=k){
			cout<<ans[i]<<"\n";
		}
		else{
			cout<<"NIE\n";
		}
	}

    return 0;
}
posted @ 2025-02-06 19:46  sad_lin  阅读(31)  评论(0)    收藏  举报