一、今日计划 2021.10.28
今天没有考试。回顾了一下之前的考试情况,感觉挺多知识点、代码量都比较简单的题,自己考场没有拿满,是有点遗憾的,所以今天打算把之前模拟赛的题再做做。
模拟赛t1 (CF原题)
1.Imbalanced Array (顺便推一下我的洛谷博客:【单调栈】 - shengnan 的博客 )
题意:求一个序列所有子区间最大值减最小值之和
step0:暴力做法就是枚举左右端点,用st表求区间最值相减,即可算出每个区间的贡献,然后相加即可
发现:如果我们从每一个区间的贡献度考虑,那么需要枚举左右端点,O(n^2)起步,所以,直接求每个区间的贡献行不通
step1:再分析题目,寻找突破口:求每个区间的最值——实际上,可能有几个包含a[i]子区间的最大值都是a[i],也就是说,我们是否可以不必枚举每个区间求它的最大值,而是考虑每一个元素在哪些子区间是最大值(最小值同理)请仔细思考这一把求区间贡献转为求单个元素贡献的思考过程,这是复杂度从O(n^2)降为O(n)的关键
step2:考虑怎么求单个元素的贡献,也就是一个数a[i]在哪些范围内是该区间的最值?(下面以最大值为例,最小值同理)
所以,我们要找从a[i]开始往右第一个比a[i]大的数a[j],从a[i]开始往左第一个比a[i]大的数a[k],那么在a[j]到a[k]内的所有包含a[i]的子区间,最大值都是a[i],这可以用单调栈来实现。这样,左端点可以是在j~i任意一个,右端点可以是在i~k任意一个,根据乘法原理即可求出答案
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,a[1000005],top,s[1000005],l[1000005][2],r[1000005][2],ans;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
while(top&&a[i]<a[s[top]])--top;
l[i][0]=i-s[top];s[++top]=i;
}
memset(s,0,sizeof(s));top=0;s[0]=n+1;
for(int i=n;i>=1;i--){
while(top&&a[i]<=a[s[top]])top--;
r[i][0]=s[top]-i;s[++top]=i;
}
memset(s,0,sizeof(s));top=0;s[0]=0;
for(int i=1;i<=n;i++){
while(top&&a[i]>=a[s[top]])top--;
l[i][1]=i-s[top];s[++top]=i;
}
memset(s,0,sizeof(s));top=0;s[0]=n+1;
for(int i=n;i>=1;i--){
while(top&&a[i]>a[s[top]])top--;
r[i][1]=s[top]-i;s[++top]=i;
}
for(int i=1;i<=n;i++)ans+=(l[i][1]*r[i][1])*a[i],ans-=(l[i][0]*r[i][0])*a[i];
printf("%lld\n",ans);
return 0;
}
模拟赛t2:树上的数
#include <cstdio>
using namespace std;
int n,m,a,b,x,y,fa[5000005],q,cnt,head[5000005],res,ans;
bool vis[5000005];
struct node{int to,nxt;}e[5000005];
void insert(int u,int v){
e[++cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt;
}
void dfs(int u){
if(vis[u])return;vis[u]=1;ans--;
for(int i=head[u];i;i=e[i].nxt)dfs(e[i].to);
}
int main(){
scanf("%d%d%d%d",&n,&m,&a,&b);fa[2]=1;insert(1,2);
for(int i=3;i<=n;i++){
fa[i]=((1ll*fa[i-1]*a+b)^19760817)%(i-1)+1;
insert(fa[i],i);
}
scanf("%d%d%d",&q,&x,&y);ans=n;
for(int i=1;i<=m;i++,q=(((1ll*q*x+y)^19760817)^(i<<1))%(n-1)+2)
dfs(q),res^=ans;
printf("%d\n",res);
return 0;
}
模拟赛t3 时代的眼泪
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,q,x,w[1000005],b[1000005],cnt,head[1000005];
ll c[1000005],ans[1000005],sz[1000005],siz[1000005],tmp[1000005],res[1000005];
struct node{int to,nxt;}e[2000005];
void insert(int u,int v){e[++cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt;}
ll lowbit(int x){return x&(-x);}
void update(int x,int v){while(x<=n){c[x]+=v;x+=lowbit(x);}}
ll query(int x){ll res=0;while(x){res+=c[x];x-=lowbit(x);}return res;}
void dfs1(int u,int fa){
siz[u]=query(w[u]-1);
if(fa)sz[u]=query(w[fa]-1);
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa)continue;dfs1(v,u);
}
res[u]=query(w[u]-1)-siz[u];
ans[1]+=res[u];
update(w[u],1);
if(fa)tmp[u]=query(w[fa]-1)-sz[u];
}
void dfs2(int u,int fa){
if(u!=1){
ans[u]=ans[fa]-tmp[u];
ans[u]=ans[u]+query(w[u]-1)-res[u];
}
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].to;if(v==fa)continue;dfs2(v,u);
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%d",&w[i]),b[i]=w[i];
for(int i=1,x,y;i<=n-1;i++)scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
sort(b+1,b+1+n);int len=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)w[i]=lower_bound(b+1,b+1+len,w[i])-b;
dfs1(1,0);dfs2(1,0);
for(int i=1;i<=q;i++)scanf("%d",&x),printf("%lld\n",ans[x]);
return 0;
}