题解:P3527 [POI 2011] MET-Meteors
发现暴力没什么前途,考虑一种很甜筒的做法,对每个国家进行二分,然后处理每场陨石雨。
显然这样复杂度会慢很多,但是可以发现这些国家可以一起二分,即整体二分。设 \(solve(country,l,r)\) 函数处理二分的国家集合为 \(country\),答案在区间 \([l,r]\)中。
我们进行时间在 \([l,mid]\) 中的操作(用树状数组维护),完成后对于已经满足条件的国家,用 \(solve(country_l,l,mid)\) 处理;对于不满足条件的,则将其减去 \([l,mid]\) 所提供的陨石的和,在 \(solve(country_r,mid+1,r)\) 中处理。
发现递归最多 \(O(\log m)\) 层,每层的 \(\sum|country|=n\),\(\sum r-l+1=k\),所以每层的复杂度为 \(O((n+m)\log n)\),总复杂度 \(O((n+m)\log n\log m)\)。
注意每层递归之前将树状数组清空,同时计算 \([l,mid]\) 所提供的陨石的和时,因为每个国家可能有多个空间站,可能会爆 long long,可以加特判或开 unsigned。
Code:
#include<iostream>
#include<vector>
#define lowbit(x) ((x)&(-(x)))
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=3e5+5;
typedef unsigned long long ll;
ll sum[maxn];
int ans[maxn],ap[maxn],ed[maxn],tot,in,im,ik;
struct node{
int l,r,a;
}an[maxn<<1];
vector<int> O[maxn];
inline void modify(int pos,int v){
for(int v1=pos;v1<=im;v1+=lowbit(v1))sum[v1]+=v;
}
inline ll query(int pos){
ll res=0;
for(int v1=pos;v1;v1-=lowbit(v1))res+=sum[v1];
return res;
}
inline void solve(vector<int> &v,int l,int r){
if(l==r){
for(int p:v)ans[p]=l;
return;
}
int mid=l+r>>1;
rep(v1,ed[l-1]+1,ed[mid]){
modify(an[v1].l,an[v1].a);
modify(an[v1].r+1,-an[v1].a);
}
vector<int> lv,rv;
for(int p:v){
ll t=0;
for(int v2:O[p]){
t+=query(v2);
}
if(t>=ap[p]){
lv.push_back(p);
}
else{
ap[p]-=t;
rv.push_back(p);
}
}
rep(v1,ed[l-1]+1,ed[mid]){
modify(an[v1].l,-an[v1].a);
modify(an[v1].r+1,an[v1].a);
}
solve(lv,l,mid);
solve(rv,mid+1,r);
}
int main()
{
cin>>in>>im;
rep(v1,1,im){
int io;
scanf("%d",&io);
O[io].push_back(v1);
}
rep(v1,1,in)scanf("%d",ap+v1);
scanf("%d",&ik);
rep(v1,1,ik){
int il,ir,ia;
scanf("%d %d %d",&il,&ir,&ia);
if(il<=ir)an[++tot]={il,ir,ia};
else{
an[++tot]={il,im,ia};
an[++tot]={1,ir,ia};
}
ed[v1]=tot;
}
ed[ik+1]=tot;
vector<int> st;
rep(v1,1,in)st.push_back(v1);
solve(st,1,ik+1);
rep(v1,1,in){
if(ans[v1]>ik)printf("NIE\n");
else printf("%d\n",ans[v1]);
}
return 0;
}

浙公网安备 33010602011771号