[COTS/CETS 2018] 直方图 Histogram 题解
从部分分
对于每个高度
接下来考虑
于是考虑开一个线段树,对于每个
- 对于上述情况(1),需要查询
\sum\limits_{w=w_{\min}}^n c_w ,即区间和; - 对于上述情况(2),需要更新连续段形态:加入 / 删除一个长度为
k 的区间,有k-w+1(1\le w\le k) 个底边长为w 的矩形被加入 / 删除,即区间加一个等差数列。
上面两个操作可以使用树状数组维护:具体维护方法可以参照该教程;而连续段形态可以使用 std::set 维护。时间复杂度
放代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
namespace IAOI_lib{
template<typename T> class fenwick_tree{
private:
vector<T> t;
public:
fenwick_tree(){}
void resize(int n){
t.resize(n);
}
fenwick_tree(int n){
resize(n);
}
inline int lowbit(int x){
return x&-x;
}
inline void add(int p,T d){
if(p<0||p>=t.size())return;
t[p++]+=d;
while((p+=lowbit(p))<=t.size())t[p-1]+=d;
}
inline T sum(int p){
if(p<0||p>=t.size())return 0;
T s=t[p++];
while((p-=lowbit(p))>0)s+=t[p-1];
return s;
}
};
}
template<typename T> class arithmetic_fenwick_tree{
private:
IAOI_lib::fenwick_tree<T> c,c1,c2;
inline void add(int p,T x){
c.add(p,x),c1.add(p,x*p),c2.add(p,x*p*p);
}
public:
arithmetic_fenwick_tree(int n){
c.resize(n),c1.resize(n),c2.resize(n);
}
inline void upd(int l,int r,T a,T d){
if(l>r)return;
add(l,a),add(l+1,d-a);
add(r+1,-(a+d*(r-l+1)));
add(r+2,a+d*(r-l));
}
inline T sum(int n){
if(n<0)return 0;
T s=c.sum(n)*(n+1)*(n+2);
s-=(n*2+3)*c1.sum(n),s+=c2.sum(n);
return s/2;
}
}; // 维护区间加等差数列 & 区间和
main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n,p,c=0; cin>>n>>p;
vector<int> h(n),w(n),v={0};
for(auto &i:h)cin>>i,v.emplace_back(i);
iota(w.begin(),w.end(),0);
sort(w.begin(),w.end(),[&](int x,int y){
return h[x]>h[y];
});
for(int i=1;i<=n;i++)
v.emplace_back(p/i+!!(p%i)-1);
sort(v.begin(),v.end(),greater<>());
v.erase(unique(v.begin(),v.end()),v.end());
// 预处理出所有分界点,存储在 v 中并去重
set<pii> s; // 维护连续段
arithmetic_fenwick_tree<int> t(n);
auto add=[&](int k){t.upd(0,k-1,k,-1);};
auto del=[&](int k){t.upd(0,k-1,-k,1);};
for(int i=0,l=1,x=0;i+1<v.size();i++){
while(l<=n&&l*v[i]<p)l++;
while(x<n&&h[w[x]]>v[i+1]){
auto it=s.lower_bound(make_pair(w[x],0));
if(it!=s.end()&&it->first==w[x]+1){
auto [l,r]=*it;
del(r-l+1),add(r-l+2);
s.erase(it),s.emplace(w[x],r);
}
else s.emplace(w[x],w[x]),add(1);
it=s.lower_bound(make_pair(w[x],0));
if(it!=s.begin()&&prev(it)->second==w[x]-1){
auto [l1,r1]=*prev(it); auto [l2,r2]=*it;
del(r1-l1+1),del(r2-l2+1),add(r2-l1+1);
it=s.erase(--it),s.erase(it),s.emplace(l1,r2);
}
x++;
}
c+=(v[i]-v[i+1])*(t.sum(n-1)-t.sum(l-2));
}
cout<<c<<endl;
return 0;
}