压行小寄巧

前言

你也许因为各种原因想要压行,于是你看到了这篇文章。

本文将介绍一些压行小寄巧。

仅限 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);
}

但是三目运算符要求 abc 非空,也就是说不能实现单个 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);
}

好抽象。

后记

本文代码除“参考答案”外均未编译,如有谬误请大胆指出。

posted @   Po7ed  阅读(265)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示