压行小寄巧
前言
你也许因为各种原因想要压行,于是你看到了这篇文章。
本文将介绍一些压行小寄巧。
仅限 C++。
正文
顺序结构
有时可能很多分开的语句十分烦人。比如 if 语句后紧跟的代码块如果超过一句,就要写大括号。不关怎么说,我们希望把好几句压成一句。
,
首先你要学会 ,
。
用法:
a,b,c,...,z;
我们可以将每个语句用 ,
分隔开,以 ;
结束。它们整个只算一句代码。
同时,它们的返回值为 最后一个表达式,即上文中的 z
。
于是可以完成如下操作:
int f(int x) { return x*=2,x+1; }
该函数将返回 \(2x+1\)。当然这样的压行跟没压一样,仅供演示。
重复利用
树链剖分中,第一次 dfs 需要维护很多数组:
void dfs1(int u=r,int f=0) { dep[u]=dep[f]+1;// 比如这些 fa[u]=f; siz[u]=1; ... }
我们可以将赋值表达式的返回值重复利用,比如 siz[u]=1;
返回 \(1\)。刚好 dep[u]=dep[f]+1;
需要加 \(1\),于是:
void dfs1(int u=r,int f=0) { dep[u]=dep[fa[u]=f]+(siz[u]=1);// 变成这样 ... }
又如莫队:
inline void add(int pos) { cnt[a[pos]]++; if(cnt[a[pos]]==2)cf++; } inline void del(int pos) { cnt[a[pos]]--; if(cnt[a[pos]]==1)cf--; } void mt() { ... for(int i=1,l=1,r=0;i<=m;i++) { #define q q[i] while(q.l<l)add(--l); while(r<q.r)add(++r); while(l<q.l)del(l++); while(q.r<r)del(r--); ans[q.id]=!cf; #undef q } }
也可以压成:
void mt() { ... for(int i=1,l=1,r=0;i<=m;i++) { #define q q[i] while(q.l<l)cf+=(++cnt[a[--l]]==2);// 与 add(--l) 等价 while(r<q.r)cf+=(++cnt[a[++r]]==2);// 与 add(++r) 等价 while(l<q.l)cf-=(--cnt[a[l++]]==1);// 与 del(l++) 等价 while(q.r<r)cf-=(--cnt[a[r--]]==1);// 与 del(r--) 等价 ans[q.id]=!cf; #undef q } }
分支结构
那么如何使用压行实现分支结构 (if、else)呢?
首先需要了解三目运算符:a?b:c
。当 a
为真时,返回 b
,否则返回 c
。
于是可以完成如下操作:
int Max(int a,int b) { return (a>b?a:b); // 等价于: if(a>b)return a; return b; } int gcd(int a,int b) { return (b?gcd(b,a%b):a); // 等价于: if(b==0)return a; return gcd(b,a%b); }
但是三目运算符要求 a
、b
、c
非空,也就是说不能实现单个 if。
注意到 &&
、||
运算符有短路的特性,也就是说:
if(a)b; // 等价于 (a)&&(b) if(!a)b; // 等价于 (a)||(b)
注意 b
的返回值需能够强制转换为 bool
,否则会 CE。
于是如果 b
无法满足上述条件,就需要用到 ,
:
if(a)b; // 等价于 (a)&&(b,1)// 1 也可以为 0 if(!a)b; // 等价于 (a)||(b,1)// 1 也可以为 0
代码中使用 ,1
还是 ,0
视实际情况(需要的返回值)而定。
比如如果需要整个语句返回真(1),则可以使用 ((a)&&(b,1),1)
或 (a)||(b,1)
。可以灵活处理。
小练习
将以下函数压行:
int dep[N],siz[N],fa[N],son[N]; void init(int u=r,int f=0) { dep[u]=dep[f]+1; fa[u]=f; siz[u]=1; for(int v:e[u]) { if(v!=f) { init(v,u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) { son[u]=v; } } } } int top[N],dfn[N],rnk[N],dfncnt=1; void dfs(int u=r,int t=r) { top[u]=t; dfn[u]=dfncnt++; rnk[dfn[u]]=u; if(son[u]) { dfs(son[u],t); } else { return; } for(int v:e[u]) { if(v!=fa[u]&&v!=son[u]) { dfs(v,v); } } }
参考答案:
int dep[N],siz[N],fa[N],son[N]; void init(int u=r,int f=0) { dep[u]=dep[fa[u]=f]+(siz[u]=1); for(int v:e[u])(v==f)||(init(v,u),siz[u]+=siz[v],(siz[son[u]]<siz[v])&&(son[u]=v)); } int top[N],dfn[N],rnk[N],dfncnt=1; void dfs(int u=r,int t=r) { top[rnk[dfn[u]=dfncnt++]=u]=t,son[u]&&(dfs(son[u],t),1); for(int v:e[u])(v!=fa[u]&&v!=son[u])&&(dfs(v,v),1); }
好抽象。
后记
本文代码除“参考答案”外均未编译,如有谬误请大胆指出。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程