专栏文章
题解:P14379 【MX-S9-T2】「LAOI-16」摩天大楼
P14379题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minbizbg
- 此快照首次捕获于
- 2025/12/01 23:42 3 个月前
- 此快照最后确认于
- 2025/12/01 23:42 3 个月前
计算 的过程
正着计算有多少种方法可以使 不太好解决,因此我们可以计算有多少个 ,再拿总的减去这个值就行了。下面我们来想什么时候 。
对于一对 ,我们进行分类讨论。
-
若 中没有 ,那么就可以最低高度就永远等于 , 。
-
若 中有 ,设 中 为最后一个满足 的点。
- 若 ,那么令 ,则 右半部分的最低高度为 ,而左半段不为 , 。对称过来也可以得到 时同样有 。
- 若 且 ,类比探究 对 的影响可以得到 对 的影响,即当 中存在 时,只有当 且 时 ,但因为这种情况前提条件为 且 ,所以在这种情况下当 中存在 时就一定有 。
处理维护操作
我们通过上述方法可以将问题转化成总方案减去 的方案,而 的方案即为连续的不含 的序列的贡献加上连续的不含 的序列中 的贡献。其中若长度为 ,由组合得贡献为 。
因此,我们仅需处理上述序列长度的贡献即可。用线段树存储。两个子节点合并时,只有两个节点都存在多端合法序列即存在边界时才累加到总的计数器上。
为了求出上一次修改到下一次修改总计数器的改变量,对于每一个节点的贡献,设为其两个子节点合并时产生的贡献即可,这样就不会因某一段序列的改变而对其相邻序列的贡献产生影响。修改总计数器时减去这个节点上一次修改时的贡献在加上这一次修改时的贡献即可。
CPP#include <bits/stdc++.h>
#define int long long//不开long long过不了
using namespace std;
const int maxn=1e6+1e1;
struct Node{
int lsum,rsum;
bool duan;
};
Node a[maxn*4][3];//两个线段树存储两种不同情况
int now[maxn];
int gong[maxn*4][3];
int n,T;
int sum,zong;
int lc(int x){return 2*x;};
int rc(int x){return 2*x+1;};
int suan(int x){return (x*(x-1))/2;};
int pushup(int x,int flag){//合并操作
int res=0;
if(a[lc(x)][flag].duan==1&&a[rc(x)][flag].duan==1){
res=suan(a[lc(x)][flag].rsum+a[rc(x)][flag].lsum);
a[x][flag].lsum=a[lc(x)][flag].lsum;
a[x][flag].rsum=a[rc(x)][flag].rsum;
}
if(a[lc(x)][flag].duan==1||a[rc(x)][flag].duan==1){
a[x][flag].duan=1;
if(a[lc(x)][flag].duan==1&&a[rc(x)][flag].duan==0){
a[x][flag].lsum=a[lc(x)][flag].lsum;
a[x][flag].rsum=a[lc(x)][flag].rsum+a[rc(x)][flag].lsum;
}
if(a[lc(x)][flag].duan==0&&a[rc(x)][flag].duan==1){
a[x][flag].rsum=a[rc(x)][flag].rsum;
a[x][flag].lsum=a[rc(x)][flag].lsum+a[lc(x)][flag].rsum;
}
}
else{
a[x][flag].duan=0;
a[x][flag].lsum=a[lc(x)][flag].lsum+a[rc(x)][flag].lsum;
a[x][flag].rsum=a[lc(x)][flag].lsum+a[rc(x)][flag].rsum;
}
return res;
}
void build(int rt,int l,int r,int flag){
if(l==r){
if(flag==0){
if(now[l]==1||now[l]==-1){
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=1;
}
else{
a[rt][flag].rsum=a[rt][flag].lsum=1;
a[rt][flag].duan=0;
}
}
else{
if(now[l]==2||now[l]==-1){
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=1;
}
else if(now[l]==1){
a[rt][flag].lsum=a[rt][flag].rsum=1;
a[rt][flag].duan=0;
}
else{
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=0;
}
}
return ;
}
int mid=(l+r)/2;
build(lc(rt),l,mid,flag);
build(rc(rt),mid+1,r,flag);
gong[rt][flag]=pushup(rt,flag);
sum=sum+gong[rt][flag];
return ;
}
void gai(int rt,int l,int r,int p,int q,int flag){
if(l==r){
if(flag==0){
if(q==1){
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=1;
}
else{
a[rt][flag].rsum=a[rt][flag].lsum=1;
a[rt][flag].duan=0;
}
}
else{
if(q==2){
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=1;
}
else if(q==1){
a[rt][flag].lsum=a[rt][flag].rsum=1;
a[rt][flag].duan=0;
}
else{
a[rt][flag].lsum=a[rt][flag].rsum=0;
a[rt][flag].duan=0;
}
}
return ;
}
int mid=(l+r)/2;
if(p<=mid) gai(lc(rt),l,mid,p,q,flag);
if(p>=mid+1) gai(rc(rt),mid+1,r,p,q,flag);
int res=pushup(rt,flag);
sum=sum-gong[rt][flag]+res;
gong[rt][flag]=res;
return ;
}
signed main() {
// freopen("1.in","r",stdin);
scanf("%lld%lld",&n,&T);
zong=suan(n);
for(int i=1;i<=n;i++) scanf("%lld",&now[i]);
now[0]=-1;now[n+1]=-1;
build(1,0,1+n,0);//连续不包含1的长度
build(1,0,1+n,1);//不含2的长度
while(T--){
int x,y;
scanf("%lld%lld",&x,&y);
gai(1,0,1+n,x,y,1);
gai(1,0,1+n,x,y,0);
now[x]=y;
printf("%lld\n",zong-sum);
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...