题目链接:

CSTC2018暴力写挂

题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最大,其中dep为第一棵树中的深度,dep'为第二棵树中的深度,lca为两点的最近公共祖先。注意:a与b可以相同!

本题讲解两种做法,其中第一种做法常数较小且比较好写,第二种做法思路比较奇特。为了方便讲解,设两点在第一棵树中的距离为$dis(x,y)$

解法一

题中给的式子显然不能直接做,我们将它变换一下(设答案的点对为(x,y)):

$dep(x)+dep(y)-dep(lca)-dep'(lca)$

$=\frac{1}{2}(dep(x)+dep(y)-2*dep(lca)+dep(x)+dep(y))-dep'(lca)$

$=\frac{1}{2}(dis(x,y)+dep(x)+dep(y))-dep'(lca)$

我们对第一棵树多叉树转二叉树(详见边分治讲解)然后进行边分治。

对于每次分治,设一个点到分治中心边的距离为$d(x)$,那么式子就变成了$\frac{1}{2}(d(x)+d(y)+value+dep(x)+dep(y))-dep'(lca)$,其中$value$为分治中心边的边权。

我们将一个点在第二棵树上的点权看成是$v(x)=d(x)+dep(x)$,答案就是$v(x)+v(y)+value-dep'(lca)$。

对于每次边分治将分治联通块内所有点在第二棵树上的建出虚树,同时将分治联通块以分治中心边为界限分成两部分,将一部分的点标为黑点,将另一部分的点标为白点。

那么对于虚树中的一个点,以它为$lca$的最大答案就是在它的两个不同子树中分别选出一个黑点和一个白点使这两个点的点权和最大。

我们在虚树上进行树形DP,每个点维护这个点在虚树上的子树中黑点的最大点权及白点的最大点权。

对于每个点回溯时分别将它每个子树的信息合并上来并在合并时更新答案,这样就保证了当前点一定是所维护的最大点权黑点和最大点权白点的lca。

注意求$LCA$时不能比较带权深度而要比较不带权深度。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define INF (1<<30)
#define pr pair<int,ll>
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
ll rd2() {ll x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
int n,m;
int x,y;
ll ans;
ll z;
int cnt;
int col[400010];
struct miku
{
int x;
ll val;
}t[400010];
namespace virtual_tree
{
ll res;
int tot;
int top;
int dfn=0;
ll mid_edge;
ll d[400010];
ll v[400010];
int s[400010];
ll val[800010];
int st[400010];
int to[800010];
int lg[800010];
int vis[400010];
int dep[400010];
int head[400010];
int next[800010];
int dp[400010][2];
int f[800010][20];
vector<int>q[400010];
inline void add(int x,int y,ll z)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
inline bool cmp(const miku &a,const miku &b)
{
return s[a.x]<s[b.x];
}
void dfs(int x,int fa)
{
f[++dfn][0]=x;
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
d[to[i]]=d[x]+val[i];
dfs(to[i],x);
f[++dfn][0]=x;
}
}
}
inline int mn(int x,int y)
{
return dep[x]<dep[y]?x:y;
}
inline void ST()
{
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=19;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
f[i][j]=mn(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
inline int lca(int x,int y)
{
x=s[x],y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return mn(f[x][len],f[y-(1<<len)+1][len]);
}
inline void insert(int x)
{
int fa=lca(x,st[top]);
if(!vis[fa])
{
vis[fa]=1;
v[fa]=-1ll<<60;
dp[fa][0]=dp[fa][1]=0;
}
while(top>1&&dep[st[top-1]]>=dep[fa])
{
q[st[top-1]].push_back(st[top]);
top--;
}
if(fa!=st[top])
{
q[fa].push_back(st[top]);
st[top]=fa;
}
st[++top]=x;
}
inline int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
return v[x]>v[y]?x:y;
}
inline void query(int x,int y)
{
if(!x||!y)
{
return ;
}
res=max(res,v[x]+v[y]);
}
void tree_dp(int x)
{
int len=q[x].size();
for(int i=0;i<len;i++)
{
int to=q[x][i];
tree_dp(to);
res=-1ll<<60;
query(dp[x][0],dp[to][1]);
query(dp[x][1],dp[to][0]);
ans=max(ans,res+mid_edge-2*d[x]);
dp[x][0]=merge(dp[x][0],dp[to][0]);
dp[x][1]=merge(dp[x][1],dp[to][1]);
}
vis[x]=0;
q[x].clear();
}
inline void build(ll value)
{
mid_edge=value;
for(int i=1;i<=cnt;i++)
{
vis[t[i].x]=1;
v[t[i].x]=t[i].val;
dp[t[i].x][col[t[i].x]-1]=t[i].x;
dp[t[i].x][(col[t[i].x]-1)^1]=0;
col[t[i].x]=0;
}
sort(t+1,t+1+cnt,cmp);
top=0;
if(t[1].x!=1)
{
st[++top]=1;
}
for(int i=1;i<=cnt;i++)
{
insert(t[i].x);
}
while(top>1)
{
q[st[top-1]].push_back(st[top]);
top--;
}
tree_dp(1);
}
inline void work()
{
dfs(1,0);
ST();
}
};
namespace edge_partation
{
int tot;
int num;
int root;
ll d[800010];
ll val[1600010];
int to[1600010];
int vis[800010];
int head[800010];
int size[800010];
int next[1600010];
vector<pr>v[400010];
inline void push(int x,int y,ll z)
{
v[x].push_back(make_pair(y,z));
}
inline void add(int x,int y,ll z)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
void rebuild(int x,int fa)
{
int tmp=0;
int last=0;
int len=v[x].size();
for(int i=0;i<len;i++)
{
int to=v[x][i].first;
int val=v[x][i].second;
if(to==fa)
{
continue;
}
tmp++;
if(tmp==1)
{
add(x,to,val);
add(to,x,val);
last=x;
}
else if(tmp==len-(x!=1))
{
add(last,to,val);
add(to,last,val);
}
else
{
m++;
add(last,m,0);
add(m,last,0);
last=m;
add(m,to,val);
add(to,m,val);
}
}
for(int i=0;i<len;i++)
{
if(v[x][i].first==fa)
{
continue;
}
rebuild(v[x][i].first,x);
}
}
void dfs(int x,int fa)
{
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
d[to[i]]=d[x]+val[i];
dfs(to[i],x);
}
}
}
void getroot(int x,int fa,int sum)
{
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[i>>1]&&to[i]!=fa)
{
getroot(to[i],x,sum);
size[x]+=size[to[i]];
int mx_size=max(size[to[i]],sum-size[to[i]]);
if(mx_size<num)
{
num=mx_size;
root=i;
}
}
}
}
void dfs2(int x,int fa,ll dep,int opt)
{
if(x<=n)
{
col[x]=opt;
t[++cnt]=(miku){x,d[x]+dep};
}
for(int i=head[x];i;i=next[i])
{
if(!vis[i>>1]&&to[i]!=fa)
{
dfs2(to[i],x,dep+val[i],opt);
}
}
}
void partation(int x,int sum)
{
num=INF;
getroot(x,0,sum);
if(num==INF)
{
return ;
}
int now=root;
vis[now>>1]=1;
cnt=0;
dfs2(to[now],0,0ll,1);
dfs2(to[now^1],0,0ll,2);
virtual_tree::build(val[now]);
int sz=size[to[now]];
partation(to[now],sz);
partation(to[now^1],sum-sz);
}
inline void work()
{
tot=1;
rebuild(1,0);
dfs(1,0);
partation(1,m);
}
};
int main()
{
m=n=rd();
ans=-1ll<<60;
for(int i=1;i<n;i++)
{
x=rd(),y=rd(),z=rd2();
edge_partation::push(x,y,z);
edge_partation::push(y,x,z);
}
for(int i=1;i<n;i++)
{
x=rd(),y=rd(),z=rd2();
virtual_tree::add(x,y,z);
virtual_tree::add(y,x,z);
}
virtual_tree::work();
edge_partation::work();
ans>>=1;
for(int i=1;i<=n;i++)
{
ans=max(ans,edge_partation::d[i]-virtual_tree::d[i]);
}
printf("%lld",ans);
}

解法二

同样将原式转化一下:

$dep(x)+dep(y)-dep(lca)-dep'(lca)$

$=dep(y)+(dep(x)-dep(lca))-dep'(lca)$(这好像除了加了个括号、换了下位置啥都没变啊QAQ)

咳咳...我们先不关注这个,同样对于第一棵树进行边分治,对于一次分治,将当前分治联通块以分治中心边为界分成了两部分,我们设这两部分为$S$和$T$。

如果每次边分治时都以当前联通块在原树中深度最小的点为根找分治中心边,那么分治中心边就是一条从原树的父节点连向子节点的边,那么$S$和$T$中就一定有一个是原树的一棵子树。

我们假设$T$是原树的一棵子树,那么显然$S$距离根节点(即$1$号点)更近。

假设$x\subseteq S,y\subset T,y'\subseteq T$,那么$x$与$y$的$lca$一定不在$T$中,也就是说$lca(x,y)$一定等于$lca(x,y')$。

所以对于$S$中的一个点$x$,它与$T$中任意一个点的$lca$都是相同的,假设分治中心边属于$T$的端点为$v$,那么只要求出$lca(x,v)$就求出了$x$与任意$T$中节点的$lca$。

那么对于$S$中的点,我们将它在第二棵树中的点权设为$v(x)=dep(x)-dep(lca(x,v))$;

对于$T$中的点,我们将它在第二棵树中的点权设为$v(x)=dep(x)$。

再像解法一那样对于分治联通块在第二棵树中建出虚树并在虚树上树形DP即可。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define INF (1<<30)
#define pr pair<int,ll>
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
ll rd2() {ll x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
int n,m;
int x,y;
ll ans;
ll z;
int cnt;
int col[400010];
struct miku
{
int x;
ll val;
}t[400010];
namespace virtual_tree
{
ll res;
int tot;
int top;
int dfn=0;
ll d[400010];
ll v[400010];
int s[400010];
ll val[800010];
int st[400010];
int to[800010];
int lg[800010];
int vis[400010];
int dep[400010];
int head[400010];
int next[800010];
int dp[400010][2];
int f[800010][20];
vector<int>q[400010];
inline void add(int x,int y,ll z)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
inline bool cmp(const miku &a,const miku &b)
{
return s[a.x]<s[b.x];
}
inline void dfs(int x,int fa)
{
f[++dfn][0]=x;
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
d[to[i]]=d[x]+val[i];
dfs(to[i],x);
f[++dfn][0]=x;
}
}
}
inline int mn(int x,int y)
{
return dep[x]<dep[y]?x:y;
}
inline void ST()
{
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=19;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
f[i][j]=mn(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
inline int lca(int x,int y)
{
x=s[x],y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return mn(f[x][len],f[y-(1<<len)+1][len]);
}
inline void insert(int x)
{
int fa=lca(x,st[top]);
if(!vis[fa])
{
vis[fa]=1;
v[fa]=-1ll<<60;
dp[fa][0]=dp[fa][1]=0;
}
while(top>1&&dep[st[top-1]]>=dep[fa])
{
q[st[top-1]].push_back(st[top]);
top--;
}
if(fa!=st[top])
{
q[fa].push_back(st[top]);
st[top]=fa;
}
st[++top]=x;
}
inline int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
return v[x]>v[y]?x:y;
}
inline void query(int x,int y)
{
if(!x||!y)
{
return ;
}
res=max(res,v[x]+v[y]);
}
inline void tree_dp(int x)
{
int len=q[x].size();
for(int i=0;i<len;i++)
{
int to=q[x][i];
tree_dp(to);
res=-1ll<<60;
query(dp[x][0],dp[to][1]);
query(dp[x][1],dp[to][0]);
ans=max(ans,res-d[x]);
dp[x][0]=merge(dp[x][0],dp[to][0]);
dp[x][1]=merge(dp[x][1],dp[to][1]);
}
vis[x]=0;
q[x].clear();
}
inline void build()
{
for(int i=1;i<=cnt;i++)
{
vis[t[i].x]=1;
v[t[i].x]=t[i].val;
dp[t[i].x][col[t[i].x]-1]=t[i].x;
dp[t[i].x][(col[t[i].x]-1)^1]=0;
col[t[i].x]=0;
}
sort(t+1,t+1+cnt,cmp);
top=0;
if(t[1].x!=1)
{
st[++top]=1;
}
for(int i=1;i<=cnt;i++)
{
insert(t[i].x);
}
while(top>1)
{
q[st[top-1]].push_back(st[top]);
top--;
}
tree_dp(1);
}
inline void work()
{
dfs(1,0);
ST();
}
};
namespace edge_partation
{
int tot;
int num;
int root;
int dfn=0;
ll d[800010];
int s[800010];
int lg[1600010];
ll val[1600010];
int to[1600010];
int vis[800010];
int dep[800010];
int head[800010];
int size[800010];
int next[1600010];
int f[1600010][21];
vector<pr>v[400010];
inline void push(int x,int y,ll z)
{
v[x].push_back(make_pair(y,z));
}
inline void add(int x,int y,ll z)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
inline void rebuild(int x,int fa)
{
int tmp=0;
int last=0;
int len=v[x].size();
for(int i=0;i<len;i++)
{
int to=v[x][i].first;
int val=v[x][i].second;
if(to==fa)
{
continue;
}
tmp++;
if(tmp==1)
{
add(x,to,val);
add(to,x,val);
last=x;
}
else if(tmp==len-(x!=1))
{
add(last,to,val);
add(to,last,val);
}
else
{
m++;
add(last,m,0);
add(m,last,0);
last=m;
add(m,to,val);
add(to,m,val);
}
}
for(int i=0;i<len;i++)
{
if(v[x][i].first==fa)
{
continue;
}
rebuild(v[x][i].first,x);
}
}
inline void dfs(int x,int fa)
{
f[++dfn][0]=x;
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
d[to[i]]=d[x]+val[i];
dfs(to[i],x);
f[++dfn][0]=x;
}
}
}
inline int mn(int x,int y)
{
return dep[x]<dep[y]?x:y;
}
inline void ST()
{
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=20;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
f[i][j]=mn(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
inline int lca(int x,int y)
{
x=s[x],y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return mn(f[x][len],f[y-(1<<len)+1][len]);
}
inline void getroot(int x,int fa,int sum)
{
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[i>>1]&&to[i]!=fa)
{
getroot(to[i],x,sum);
size[x]+=size[to[i]];
int mx_size=max(size[to[i]],sum-size[to[i]]);
if(mx_size<num)
{
num=mx_size;
root=i;
}
}
}
}
inline void dfs2(int x,int fa,int rt,int opt)
{
if(x<=n)
{
col[x]=opt;
ll value=rt?d[x]-d[lca(x,rt)]:d[x];
t[++cnt]=(miku){x,value};
}
for(int i=head[x];i;i=next[i])
{
if(!vis[i>>1]&&to[i]!=fa)
{
dfs2(to[i],x,rt,opt);
}
}
}
inline void partation(int x,int sum)
{
num=INF;
getroot(x,0,sum);
if(num==INF)
{
return ;
}
int now=root;
vis[now>>1]=1;
cnt=0;
dfs2(x,0,to[now],1);
dfs2(to[now],0,0,2);
virtual_tree::build();
int sz=size[to[now]];
partation(to[now],sz);
partation(x,sum-sz);
}
inline void work()
{
tot=1;
rebuild(1,0);
dfs(1,0);
ST();
partation(1,m);
}
};
int main()
{
m=n=rd();
ans=-1ll<<60;
for(int i=1;i<n;i++)
{
x=rd(),y=rd(),z=rd2();
edge_partation::push(x,y,z);
edge_partation::push(y,x,z);
}
for(int i=1;i<n;i++)
{
x=rd(),y=rd(),z=rd2();
virtual_tree::add(x,y,z);
virtual_tree::add(y,x,z);
}
virtual_tree::work();
edge_partation::work();
for(int i=1;i<=n;i++)
{
ans=max(ans,edge_partation::d[i]-virtual_tree::d[i]);
}
printf("%lld",ans);
}

BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP的更多相关文章

  1. LOJ 2553 「CTSC2018」暴力写挂——边分治+虚树

    题目:https://loj.ac/problem/2553 第一棵树上的贡献就是链并,转化成 ( dep[ x ] + dep[ y ] + dis( x, y ) ) / 2 ,就可以在第一棵树上 ...

  2. BZOJ5341: [Ctsc2018]暴力写挂

    BZOJ5341: [Ctsc2018]暴力写挂 https://lydsy.com/JudgeOnline/problem.php?id=5341 分析: 学习边分治. 感觉边分治在多数情况下都能用 ...

  3. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  4. UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树

    传送门--UOJ 传送门--LOJ 跟隔壁通道是一个类型的 要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象-- 第二棵树上的LCA显然是动不了的,因为没有其他的量 ...

  5. UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并

    原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$ ...

  6. [LOJ#2553][CTSC2018]暴力写挂

    [LOJ#2553][CTSC2018]暴力写挂 试题描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...

  7. [CTSC2018]暴力写挂——边分树合并

    [CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分 ...

  8. 【BZOJ-3572】世界树 虚树 + 树形DP

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status ...

  9. bzoj 2286(虚树+树形dp) 虚树模板

    树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5002  Sol ...

随机推荐

  1. Django 笔记分享

    Django是一个基于MVC构造的框架.但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model).模板(Template)和视图(Views), ...

  2. loj#6074. 「2017 山东一轮集训 Day6」子序列(矩阵乘法 dp)

    题意 题目链接 Sol 设\(f[i][j]\)表示前\(i\)个位置中,以\(j\)为结尾的方案数. 转移的时候判断一下\(j\)是否和当前位置相同 然后发现可以用矩阵优化,可以分别求出前缀积和逆矩 ...

  3. Salesforce 小知识:大量“子记录”的处理方法

    大量"子记录"的存放 例子:系统中导入了很多"联系人"(Contact)记录,它们没有具体所属的"客户"(Account)记录.那么我们就要 ...

  4. ARM汇编指令集_学习笔记(1)

    一.什么是ARM汇编? 运行在ARM处理器上的汇编语言就叫ARM汇编. C程序运行在X86平台,底层就是X86汇编:运行在ARM平台,底层就是ARM汇编.ARM汇编与X86汇编有显著区别. X86属于 ...

  5. Docker Data Center系列(二)- UCP安装指南

    本系列文章演示如何搭建一个mini的云平台和DevOps实践环境. 基于这套实践环境,可以部署微服务架构的应用栈,演练提升DevOps实践能力. 1 系统要求 1.1 硬件和软件要求 Linux内核版 ...

  6. 从0开始的Python学习005运算符与表达式

     地三鲜 土豆+茄子+青椒=地三鲜 这就是一个表达式,表达式是由运算符和操作数组成的. 土豆.茄子和青椒是操作数,炒是运算符,而地三鲜就是最后结果也就是这个表达式的值. 表达式 一个表达式可以分解为运 ...

  7. Spring MVC 数据绑定 (四)

    完整的项目案例: springmvc.zip 目录 实例 项目结构路径: 一.配置web.xml <?xml version="1.0" encoding="UTF ...

  8. Python装饰器、内置函数之金兰契友

    装饰器:装饰器的实质就是一个闭包,而闭包又是嵌套函数的一种.所以也可以理解装饰器是一种特殊的函数.因为程序一般都遵守开放封闭原则,软件在设计初期不可能把所有情况都想到,所以一般软件都支持功能上的扩展, ...

  9. 【原】Java学习笔记009 - 阶段测试

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 1.需求:打印如下 ...

  10. js获取时间相关函数

    js获取时间函数 var myDate = new Date; var year = myDate.getFullYear();//获取当前年 var yue = myDate.getMonth()+ ...