CF1109F Sasha and Algorithm of Silence's Sounds
XXV.Sasha and Algorithm of Silence's Sounds
假设我们把区间里的格子连出来,然后发现出现一个环,则我们可以肯定地说,所有具有作为子区间的区间,都是不合法的。
于是我们对于每个位置,都可以找出其最右边的不成环的位置。使用two-pointers思想,用LCT维护当前建出的图,即可做到求解极大区间。
下面我们只需要找出中有多少个满足是树即可。显然因为已经保证无环了,所以我们只需要保证即可。使用线段树维护即可把此部分也优化至。
则总复杂度。
(似乎因为CF不太支持 #define pushup (something)
用在线段树里,我连着MLE了好几天才发现是这个缘故,以后还是老老实实写函数式pushup
罢)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,lim,a[1010][1010],dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
pair<int,int>p[1000100];
ll res;
namespace LCT{
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct Link_Cut_Tree{
int fa,ch[2];
bool rev;
}t[200100];
inline int identify(int x){
if(x==t[t[x].fa].ch[0])return 0;
if(x==t[t[x].fa].ch[1])return 1;
return -1;
}
inline void REV(int x){t[x].rev^=1,swap(lson,rson);}
inline void pushdown(int x){
if(!t[x].rev)return;
if(lson)REV(lson);
if(rson)REV(rson);
t[x].rev=0;
}
inline void rotate(int x){
register int y=t[x].fa,z=t[y].fa,dirx=identify(x),diry=identify(y),b=t[x].ch[!dirx];
if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
if(b)t[b].fa=y;t[y].ch[dirx]=b;
t[y].fa=x,t[x].ch[!dirx]=y;
}
inline void pushall(int x){if(identify(x)!=-1)pushall(t[x].fa);pushdown(x);}
inline void splay(int x){for(pushall(x);identify(x)!=-1;rotate(x))if(identify(t[x].fa)!=-1)rotate(identify(x)==identify(t[x].fa)?t[x].fa:x);}
inline void access(int x){for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y;}
inline void makeroot(int x){access(x),splay(x),REV(x);}
inline int findroot(int x){access(x),splay(x),pushdown(x);while(lson)x=lson,pushdown(x);splay(x);return x;}
inline void split(int x,int y){makeroot(x),access(y),splay(y);}
inline bool link(int x,int y){if(findroot(x)==findroot(y))return false;makeroot(x),t[x].fa=y;return true;}
inline void cut(int x,int y){split(x,y),t[y].ch[0]=t[x].fa=0;}
#undef lson
#undef rson
}
namespace SG{
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
struct SegTree{
int mn,num,tag;
}seg[800100];
void ADD(int x,int y){seg[x].mn+=y,seg[x].tag+=y;}
void pushdown(int x){ADD(lson,seg[x].tag),ADD(rson,seg[x].tag),seg[x].tag=0;}
void pushup(int x){
seg[x].mn=min(seg[lson].mn,seg[rson].mn),seg[x].num=0;
if(seg[x].mn==seg[lson].mn)seg[x].num+=seg[lson].num;
if(seg[x].mn==seg[rson].mn)seg[x].num+=seg[rson].num;
}
void build(int x,int l,int r){
if(l==r){seg[x].mn=0,seg[x].num=1;return;}
build(lson,l,mid),build(rson,mid+1,r),pushup(x);
}
void modify(int x,int l,int r,int L,int R,int val){
if(l>R||r<L)return;
if(L<=l&&r<=R){ADD(x,val);return;}
pushdown(x),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),pushup(x);
}
int query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(L<=l&&r<=R)return seg[x].mn==1?seg[x].num:0;
pushdown(x);
return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
}
#undef lson
#undef rson
#undef mid
}
#define P a[x+dx[i]][y+dy[i]]
int main(){
scanf("%d%d",&n,&m),lim=n*m;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),p[a[i][j]]=make_pair(i,j);
SG::build(1,1,lim);
for(int l=1,r=1;l<=lim;l++){
while(r<=lim){
int x=p[r].first,y=p[r].second;
int cnt=0;
for(int i=0;i<4;i++){
if(!(P>=l&&P<r))continue;
cnt++;
if(LCT::link(r,P))continue;
for(i--;i>=0;i--)if(P>=l&&P<r)LCT::cut(r,P);
cnt=-1;
break;
}
if(cnt==-1)break;
SG::modify(1,1,lim,r,lim,-cnt);
SG::modify(1,1,lim,r,r,r-l+1);
r++;
}
res+=SG::query(1,1,lim,l,r-1);
SG::modify(1,1,lim,l,r-1,-1);
int x=p[l].first,y=p[l].second;
for(int i=0;i<4;i++)if(P>=l&&P<r)LCT::cut(l,P),SG::modify(1,1,lim,P,lim,1);
}
printf("%lld\n",res);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?