SS241102C. 墙(wall)
SS241102C. 墙(wall)
原题:P10764 [BalticOI 2024] Wall
题意
给你一面墙,第 \(i\) 列的高度是 \(a_i\) 或者 \(b_i\)。你在墙上装水。若第 \(i\) 列的墙的高度是 \(h_i\),位置 \(i\) 的积水高度是 \(H_i\) 当且仅当存在 \(h_{j<i}\ge H_i\) 和 \(h_{j>i} \ge H_i\)。
求所有情况的 \(\sum H_i-h_i\)。
对 \(10^9 + 7\) 取模。\(n\le 3\times 10^5\)。
solution
拜谢 cjh。
暴力是枚举所有情况,然后直接枚举 \(i\) 来求。
我们把枚举情况写进求和符号内,变成求合法方案数。
其中 \(V\) 是值域最大值。
拆开贡献:
这样一个 \(H_i\) 就会在 \(j=h_i+1\sim h_i+H_i\) 的时候计贡献了。
如何求 \((j 的高度处有水(h_i 处算没水)的方案数)\)?
就是求左边最高的墙高 \(\ge j\) 且右边最高的墙高 \(\ge j\) 的方案数。
同时需要乘上一个第 \(i\) 个墙选择 \(a_i/b_i\) 的系数(\(h_i\) 必须 \(<\) j)。
即:
其中 \(L_{i,j}\) 表示 \(i\) 左边的最高的墙 \(\ge j\) 的方案数,\(R\) 类似。
然而最高 \(\ge j\) 不好算,但是 \(< j\) 是好算的。
因此设 \(L_{i,j}\) 表示 \(i\) 左边的最高的墙 \(< j\) 的方案数,\(R\) 类似。
有:
设 \(c_i=([a_i< j]+[b_i< j])\),有:
于是我们要选择枚举 \(i\) 或者 \(j\),然后维护另一维。
我们选择倒序枚举 \(j\)。
事实上其他枚举方式也是可以做的,但是比较麻烦,比如枚举 \(i\) 会出现除以 \(0\) 的操作。其他枚举方式都是不方便做的(maybe 需要维护的信息比较复杂?),至少倒序枚举 \(j\) 一定方便做。
我们要分别维护括号的三个东西。
使用线段树维护。
实际上想到使用线段树,应该是因为之前使用 \(L_{i,j}\) 的时候就发现很适合使用线段树。
抄过来看看。
当 \(j\) 变小的时候,相当于对 \(L_i\) 执行后缀 \(\div 2\) 或者 \(\times 0\) 的操作,以及对 \(R_i\) 的某些前缀执行这样的操作。
以及 \(c_i\) 也会变化,单点修改就行。
这样就可以维护了。
结论:倒序枚举值域,线段树下标维护数组下标。枚举值域,对影响到的下标,对线段树执行前缀或者后缀操作。然后求线段树全局和。线段树维护三个信息。
时间复杂度 \(O(n\log n)\)。
写起来还是……相对……也许……可能……实际上应该是挺好写的,但是感觉推式子细节比较多?应该是我太菜了的缘故。
code
我用了这么多线段树,没有任何优化(为了保证代码可读性,保证我这种蒟蒻能读懂自己的代码……),但是为什么跑到目前最优解?(大雾)
#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
constexpr int N=5e5+7,mod=1e9+7,inv=500000004;
int add(int a,int b) { return a+b>=mod ? a+b-mod : a+b; }
void _add(int &a,int b) { a=add(a,b); }
ll ksm(ll a,ll b=mod-2) {
ll s=1;
while(b) {
if(b&1) s=s*a%mod;
a=a*a%mod;
b>>=1;
}
return s;
}
int n,m;
struct pii {
int a,b;
}x[N];
struct pib {
int id;
bool ab;
};
vector<pib> vec[N<<1];
int c[N<<1];
int val;
struct tree {
int tr[N<<2];
int div[N<<2];
bool del[N<<2];
void maketag(int u,int t1,bool t2) {
if(t2) tr[u]=0,del[u]=1;
else tr[u]=1ll*tr[u]*t1%mod,div[u]=1ll*div[u]*t1%mod;
}
void pushup(int u) {
tr[u]=add(tr[u<<1],tr[u<<1|1]);
}
void pushdown(int u) {
maketag(u<<1,div[u],del[u]), maketag(u<<1|1,div[u],del[u]);
div[u]=1;
}
void build(int u,int l,int r) {
div[u]=1;
if(l==r) { tr[u]=val; return; }
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void change (int u,int l,int r,int L,int R,int t1,bool t2) {
if(del[u]) return;
if(l>=L&&r<=R) { maketag(u,t1,t2); return; }
int mid=(l+r)>>1;
pushdown(u);
if(L<=mid) change(u<<1,l,mid,L,R,t1,t2);
if(mid+1<=R) change(u<<1|1,mid+1,r,L,R,t1,t2);
pushup(u);
}
void change (int u,int l,int r,int x,int t1,bool t2) {
if(del[u]) return;
if(l==r) { maketag(u,t1,t2); return; }
int mid=(l+r)>>1;
pushdown(u);
if(x<=mid) change(u<<1,l,mid,x,t1,t2);
else change(u<<1|1,mid+1,r,x,t1,t2);
pushup(u);
}
}T1,T2,T3;
int cnt,ans;
int main() {
#ifdef LOCAL
freopen("my.out","w",stdout);
#else
freopen("wall.in","r",stdin);
freopen("wall.out","w",stdout);
#endif
sf("%d",&n);
rep(i,1,n) sf("%d",&x[i].a);
rep(i,1,n) {
sf("%d",&x[i].b);
if(x[i].a > x[i].b) swap(x[i].a,x[i].b);
c[i*2-1]=x[i].a, c[i*2]=x[i].b;
}
sort(c+1,c+(n<<1)+1);
m=unique(c+1,c+(n<<1)+1)-c-1;
rep(i,1,n) {
x[i].a=lower_bound(c+1,c+m+1,x[i].a)-c;
x[i].b=lower_bound(c+1,c+m+1,x[i].b)-c;
vec[x[i].a].push_back({i,0}), vec[x[i].b].push_back({i,1});
}
val=ksm(2,n);
T1.build(1,1,n),T2.build(1,1,n),T3.build(1,1,n);
cnt=n<<1;
val=1ll*val*inv%mod;
per(i,m,1) {
for(auto u : vec[i]) {
int id=u.id;
bool op=u.ab;
--cnt;
if(op) {
T1.change(1,1,n,id,inv,0),
T2.change(1,1,n,id,inv,0),
T3.change(1,1,n,id,inv,0);
if(id<n) T1.change(1,1,n,id+1,n,inv,0), T2.change(1,1,n,id+1,n,inv,0);
if(id>1) T1.change(1,1,n,1,id-1,inv,0), T3.change(1,1,n,1,id-1,inv,0);
}else{
T1.change(1,1,n,id,0,1),
T2.change(1,1,n,id,0,1),
T3.change(1,1,n,id,0,1);
if(id<n) T1.change(1,1,n,id+1,n,0,1), T2.change(1,1,n,id+1,n,0,1);
if(id>1) T1.change(1,1,n,1,id-1,0,1), T3.change(1,1,n,1,id-1,0,1);
}
}
int s=0;
_add(s,1ll*val*cnt%mod);
_add(s,T1.tr[1]);
_add(s,mod-add(T2.tr[1],T3.tr[1]));
_add(ans,1ll*s*(c[i]-c[i-1])%mod);
}
pf("%d\n",ans);
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18522166