【题解】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 @   sad_lin  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示