JOI 2020 Final 火灾
Posted iefnah06
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JOI 2020 Final 火灾相关的知识,希望对你有一定的参考价值。
URL
简要题意
有一个长度为n的数字序列s[1...n]
再接下来的n个时刻,按照从后往前的顺序,每个s[i]都会和s[i-1]取max(在n+1个时刻后序列肯定不会改变了,每个位置都是前缀最大值)
多次询问(t,l,r),表示第t个时刻[l,r]内数字的和
n,q 200000
解法
可以看看官方题解 https://www.ioi-jp.org/joi/2019/2020-ho/2020-ho-t5-review.pdf 的图
考虑每一个位置的数字在(n+1)*n的矩阵中的连通块(如果在取max时两个数相等,我们认为新的max值来自后面的那个)。
对每个数字用单调栈算出:
- pl[i]:左边第一个比它大的位置,不存在的话设为-1
- pr[i]:右边第一个不比它小的位置
按照pl[i]分两种情况:
- 左边的每个数都不超过它:覆盖范围是以pr[i]-1为右边界的矩形,扣去一个以pr[i]-1为有边界的直角三角形。
- 左边存在大于它的:覆盖范围是一个平行四边形,可以差分成三个直角三角形。
然后离线+树状数组即可。
注意三角形得拆成一个后缀直角梯形,扣掉一个后缀矩形。具体实现时可以把梯形和矩形的贡献分开来统计,统计梯形的贡献时每次把数轴整体右移一位。
实现
#include <bits/stdc++.h>
using namespace std;
#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,b) rng(i,0,b)
#define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define eb emplace_back
#define bg begin()
#define ed end()
#define all(x) (x).bg,(x).ed
#define si(x) int((x).size())
#define mp make_pair
#define a first
#define b second
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif
template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
using ll=long long;
using uint=unsigned int;
using pi=pair<int,int>;
using vi=vc<int>;
int topbit(signed t){
return t==0?-1:31-__builtin_clz(t);
}
int topbit(ll t){
return t==0?-1:63-__builtin_clzll(t);
}
template<class t>
struct BIT{
vc<t> buf;
int s;
BIT(int s_=0){init(s_);};
void init(int s_){buf.assign(s=s_,0);}
void add(int i,t v){
for(;i<s;i+=(i+1)&(-i-1))
buf[i]+=v;
}
t get(int i){
t res=0;
for(;i>=0;i-=(i+1)&(-i-1))
res+=buf[i];
return res;
}
t sum(int b,int e){
return get(e-1)-get(b-1);
}
/*int kth(int k){
int res=0;
for(int i=topbit(s);i>=0;i--){
int w=res+(1<<i);
if(w<=s&&buf[w-1]<=k){
k-=buf[w-1];
res=w;
}
}
return res;
}*/
};
template<class t>
struct X{
BIT<t> a,b;
int s;
X(int s_){
s=s_;
a.init(s);
b.init(s);
}
void add(int i,t v){
a.add(i,v);
b.add(i,-i*v);
}
void add(int l,int r,t v){
add(l,v);
add(r,-v);
}
t get(int i){
return i*a.get(i-1)+b.get(i-1);
}
t get(int l,int r){
return get(r)-get(l);
}
};
struct trape{
int i,v;
};
struct rect{
int l,r,v;
};
struct query{
int l,r,i;
};
const int nmax=2.1e5;
const int qmax=2.1e5;
int n,q;
int s[nmax];
int pl[nmax],pr[nmax];
vc<trape> etrape[nmax];
vc<rect> erect[nmax];
void addtrape(int i,int h,int v){
etrape[0].pb(trape{i,v});
etrape[h].pb(trape{i+h,-v});
}
void addrect(int l,int r,int h,int v){
if(l==r)return;
erect[0].pb(rect{l,r,v});
erect[h].pb(rect{l,r,-v});
}
void addtri(int l,int r,int v){
if(l==r)return;
addtrape(l,r-l,v);
addrect(r,n,r-l,-v);
}
vc<query> qs[nmax];
ll res[qmax];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>q;
rep(i,n)cin>>s[i];
{
vi st;
rep(i,n){
while(si(st)&&s[st.back()]<=s[i]){
pr[st.back()]=i;
st.pop_back();
}
if(si(st))pl[i]=st.back();
else pl[i]=-1;
st.pb(i);
}
while(si(st)){
pr[st.back()]=n;
st.pop_back();
}
}
rep(i,n){
if(pl[i]==-1){
addrect(i,pr[i],n+1,s[i]);
addtri(i+1,pr[i],-s[i]);
}else{
addtri(pl[i]+1,pr[i],s[i]);
addtri(pl[i]+1,i,-s[i]);
addtri(i+1,pr[i],-s[i]);
}
}
X<ll> xtrape(2*n+10);
X<ll> xrect(n+10);
rep(i,q){
int t,l,r;cin>>t>>l>>r;l--;
qs[t].pb(query{l,r,i});
}
int shift=n+5;
rep(t,n+1){
for(auto et:etrape[t])
xtrape.add(et.i+shift,et.v);
for(auto er:erect[t])
xrect.add(er.l,er.r,er.v);
auto get=[&](int l,int r)->ll{
return xrect.get(l,r)+xtrape.get(l+shift,r+shift);
};
for(auto dt:qs[t])
res[dt.i]=get(dt.l,dt.r);
shift--;
}
rep(i,q)
cout<<res[i]<<'
';
}
以上是关于JOI 2020 Final 火灾的主要内容,如果未能解决你的问题,请参考以下文章
loj#2334 「JOI 2017 Final」JOIOI 王国