ABC435 总结
第一次打 ABC。
A
显然地输出:
B
显然地 \(\mathcal O\left(n^3\right)\) 模拟即可。
C
考虑维护指针 \(r\),那么 \(i\) 从 \(1\) 到 \(\min(r,n)\) 遍历。
对于 \(i\),令 \(r\leftarrow\max(r,i+a_i-1)\) 即可。
最终答案即最大的 \(i\)。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=5e5;
int n,a[N+1];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=1;
for(int i=2,r=a[1];i<=r&&i<=n;i++){
ans++;
r=max(r,i+a[i]-1);
}
cout<<ans<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
D
考虑 \(x\) 染黑,那么所有能够抵达 \(x\) 的节点的答案都需要更改。考虑从 \(x\) 开始反向 DFS,标记这些点即可。如果走到的点 \(y\) 已经染色过了,则跳出递归。
时间复杂度 \(\mathcal O(n+m+q)\)。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=3e5;
int n;
bool vis[N+1];
vector<int>g[N+1];
void color(int x){
if(vis[x]){
return;
}
vis[x]=true;
for(int i:g[x]){
color(i);
}
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m;
cin>>n>>m;
while(m--){
int u,v;
cin>>u>>v;
g[v].push_back(u);
}
int q;
cin>>q;
while(q--){
int op,x;
cin>>op>>x;
switch(op){
case 1:
color(x);
break;
case 2:
cout<<(vis[x]?"Yes":"No")<<'\n';
break;
}
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
E
考虑区间推平操作(染黑),想到线段树维护。
那么线段树就可以简单地维护区间推平,之后查询白色的个数也是简单的。每个节点都维护当前区间内白色的个数即可,\([l,r]\) 对应初始值为 \(r-l+1\)。
推平就维护一个懒标记,表示是否推平即可。
但是 \(1\leq n\leq10^9\),需要动态开点。空间限制 \(\text{1GB}\),随便跑;否则也可以离散化之后做到 \(\mathcal O(q\log q)\)。
时间复杂度:\(\mathcal O(q\log n)\)。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=1e9,Q=2e5;
struct segTree{
int size;
struct node{
int l,r,value;
int lChild,rChild;
bool tag;
int size(){
return r-l+1;
}
}t[Q*100];
int create(node x){
t[++size]=x;
return size;
}
void build(int l,int r){
create({l,r,r-l+1});
}
void up(int p){
t[p].value=t[t[p].lChild].value+t[t[p].rChild].value;
}
void down(int p){
int mid=t[p].l+t[p].r>>1;
if(!t[p].lChild){
t[p].lChild=create({t[p].l,mid,mid-t[p].l+1});
}
if(!t[p].rChild){
t[p].rChild=create({mid+1,t[p].r,t[p].r-mid});
}
if(t[p].tag){
t[t[p].lChild].value=0;
t[t[p].lChild].tag=true;
t[t[p].rChild].value=0;
t[t[p].rChild].tag=true;
t[p].tag=false;
}
}
void update(int p,int l,int r){
if(l<=t[p].l&&t[p].r<=r){
t[p].value=0;
t[p].tag=true;
return;
}
down(p);
if(l<=t[t[p].lChild].r){
update(t[p].lChild,l,r);
}
if(t[t[p].rChild].l<=r){
update(t[p].rChild,l,r);
}
up(p);
}
int query(int p,int l,int r){
if(l<=t[p].l&&t[p].r<=r){
return t[p].value;
}
down(p);
int ans=0;
if(l<=t[t[p].lChild].r){
ans+=query(t[p].lChild,l,r);
}
if(t[t[p].rChild].l<=r){
ans+=query(t[p].rChild,l,r);
}
return ans;
}
}t;
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,q;
cin>>n>>q;
t.build(1,n);
while(q--){
int l,r;
cin>>l>>r;
t.update(1,l,r);
cout<<t.query(1,1,n)<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
F
记 \(a_i\) 为原题中 \(P_i\)。
显然,移走猫所在的塔更优。
容易想到,塔 \(i\) 被删除后,只能移动到左边或者右边。因此完全等价于把剩下的另一段前缀/后缀全部删除。
因此可以想到这就是把整个序列建成一棵二叉树,删除一个塔就相当于走入一棵子树(删除另一棵子树)。
因此设 \(\textit{dp}_x\) 为从 \(x\) 开始走的答案。记 \(l,r\) 分别为 \(x\) 的左右子节点,则有:
之后考虑如何建树是合法的。每次必须跳到最高的塔,等价于要求树根的 \(a\) 最大,即大根堆。并且下标应当满足 BST 性质,这就是一棵笛卡尔树。
时间复杂度 \(\mathcal O(n)\)。
赛时代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=2e5;
int n,a[N+1],lChild[N+1],rChild[N+1];
ll dfs(int x){
ll ans=0;
if(lChild[x]){
ans=max(ans,abs(x-lChild[x])+dfs(lChild[x]));
}
if(rChild[x]){
ans=max(ans,abs(x-rChild[x])+dfs(rChild[x]));
}
return ans;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
vector<int>s;
for(int i=1;i<=n;i++){
int pl=0;
while(s.size()&&a[s.back()]<a[i]){
pl=s.back();
s.pop_back();
}
if(pl){
lChild[i]=pl;
}
if(s.size()){
rChild[s.back()]=i;
}
s.push_back(i);
}
cout<<dfs(s.front())<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号