压行小寄巧
前言
你也许因为各种原因想要压行,于是你看到了这篇文章。
本文将介绍一些压行小寄巧。
仅限 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);
}
好抽象。
后记
本文代码除“参考答案”外均未编译,如有谬误请大胆指出。

浙公网安备 33010602011771号