【学习笔记】动态树Link-Cut-Tree
这是两个月前写的,看能不能搬运过来……
动态树是一类维护森林连通性的问题(已纠正,感谢ZQC巨佬),目前最(wo)常(zhi)见(hui)的动态树就是LCT(Link-Cut-Tree),然而LCT似乎是处理路径的,处理子树可能力不足。据说有一种称为Top Tree的数据结构,可以处理所有。但是学不动了Orz
LCT中最主要的是Access操作,Access(u)操作的含义是,从当前的节点u向他所在的根节点连一条重路径,这是相当于把沿路的重路径全都断开,重新拉一条从u到根的重路径。
makeroot(x)操作:
若想让u成为当前树的根节点,则可以先access(u),再splay(u),把u转为当前splay的根节点。因为splay维护的是深度,所以u没有右儿子(没有比u还要深的点,因为重链定义),所以换根就相当于一次区间翻转,交换左右子树即完成区间翻转。此时就可以打标记了。
所以,makeroot=access+splay+rev
还有一个isroot操作,超级简单,就是判断这是不是一条重路径的根,只要他的fa指针指向的节点的左右子树都不是他(证明此时这是一条虚边),那么这就是一棵子树的根节点。
link(x,y)操作:
在u和v之间连边,可以makeroot(u),再让u的父亲为v,这就相当于v本身是一棵splay,而u和v之间连了条轻边。
cut(u,v)操作:
断开u和v之间的边,可以先makeroot(u),再access(v),再splay(v),此时v的左儿子必定为u,于是断开v和v的左儿子即可。
至于翻转标记的传递,就是跟Splay一样就行了。
但标记下放有一个问题。因为splay是时时刻刻在分裂与合并的,因为要动态维护每条重链,所以在splay之前,要先把根节点到当前节点全部下放一遍标记,防止标记下放不完全。
split(x,y)操作:
split相当于把两个子树分开,考虑到我们cut的时候第一步也是分开,所以
$split=makeroot(u)+access(v)+splay(v)$
然后还要保存一些轻边(虚边),对于轻边我们需要单独记录处理。在原树上,当前重链的顶端节点与他的父亲的边即为轻边,如果不记录,树将是不完整的。
具体到代码实现,可以是当前splay的根节点的父亲即为当前splay上面的那个重链所在的splay上的点,但上面的splay的儿子并不指向当前splay的父亲,即为用splay的根节点的父亲来存储轻边。
动态树的主要时间消耗在Access上,而Access的时间复杂度是
$O(nlogn)$
好像最后在UOJ群里看到一句话:
*树剖能做的,动态树都能做,只不过有的东西动态树做起来比树剖烦的多*
好像超级有道理,因为我写的维护子树size,树剖的话天生自带,但是LCT每次Access跳轻重边的时候都要交换,超级烦。
下面是这几天做的一点题目:
1.洞穴勘测
裸的连通性询问。
#include<bits/stdc++.h>
#define N 10005
#define inf 1000000007
using namespace std;
int n,m;
struct Link_Cut_Tree{
int fa[N],c[N][],q[N],top;bool rev[N];
Link_Cut_Tree(){
top=;memset(fa,,sizeof(fa));
memset(c,,sizeof(c));
memset(rev,,sizeof(rev));
}
inline bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[x]^=;rev[l]^=;rev[r]^=;
swap(c[x][],c[x][]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][]==x);r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t;}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;}
int find(int x){
access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;
}
}T;
inline int read(){
int x=,f=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
char s[];int x,y;
n=read();m=read();
for(int i=;i<=m;i++){
scanf("%s",s);
x=read();y=read();
if(s[]=='C')T.link(x,y);
if(s[]=='D')T.cut(x,y);
if(s[]=='Q'){
int xx=T.find(x),yy=T.find(y);
if(xx==yy)puts("Yes");else puts("No");
}
}
return ;
}
2.bzoj1180 OTOCI
修改,连边,区间权值合。
其实可以先读入所有的边得到最后的树,然后离线树剖,用并查集维护边就行了
本蒟蒻还是写了Link-Cut-Tree
#include<bits/stdc++.h>
#define N 30005
#define inf 1000000000
#define yql 1000000007
#define ll long long
using namespace std;
int q,n;
struct Link_Cut_Tree{
int c[N][],fa[N],sumv[N],val[N],q[N],top[N];
bool rev[N];
void pushup(int x){
int l=c[x][],r=c[x][];sumv[x]=sumv[l]+sumv[r]+val[x];
}
void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[x]^=;rev[r]^=;rev[l]^=;
swap(c[x][],c[x][]);
}
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][]==x);r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;}
int find(int x){
access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;
}
}T;
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
n=read();
for(int i=;i<=n;i++){T.sumv[i]=read();T.val[i]=T.sumv[i];}
q=read();char s[];
while(q--){
scanf("%s",s);int x=read(),y=read();
if(s[]=='b'){
int xx=T.find(x),yy=T.find(y);
if(xx==yy)puts("no");
else puts("yes"),T.link(x,y);
}
if(s[]=='p')T.makeroot(x),T.val[x]=y,T.pushup(x);
if(s[]=='e'){
int xx=T.find(x),yy=T.find(y);
if(xx!=yy)puts("impossible");
else{
T.makeroot(x);T.access(y);T.splay(y);
printf("%d\n",T.sumv[y]);
}
}
}
return ;
}
3.NOI2014 膜法森林
考虑Kruskal求出最小生成树,每次加,如果当前的边成环,那么就在之前的边里找一个最大权的cut掉。
维护连通性,cut边,最大值询问,LCT很擅长啦~
#include<bits/stdc++.h>
#define inf 1000000007
#define N 200005
using namespace std;
int n,m,cnt,_=inf;
int f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
struct Edge{
int u,v,w,c;
bool operator<(const Edge &x)const{return w<x.w;}
}G[*N]; struct Link_Cut_Tree{
int c[N][],fa[N],q[N],rev[N],top;
int maxv[N],val[N];
inline void pushup(int x){
int l=c[x][],r=c[x][];
maxv[x]=x;
if(val[maxv[l]]>val[maxv[x]])maxv[x]=maxv[l];
if(val[maxv[r]]>val[maxv[x]])maxv[x]=maxv[r];
}
Link_Cut_Tree(){top=;memset(rev,,sizeof(rev));}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][])==x;r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;pushup(y);}
int find(int x){access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;}
int querymax(int x,int y){split(x,y);return maxv[y];}
};
Link_Cut_Tree T;
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
n=read();m=read();
for(int i=;i<=n+;i++)f[i]=i;
for(int i=;i<=m;i++){
G[i].u=read(),G[i].v=read(),G[i].w=read();G[i].c=read();
}
sort(G+,G+m+);
int tot=;
for(int i=;i<=m;i++){
int u=G[i].u,v=G[i].v,w=G[i].w,c=G[i].c;
if(find(u)==find(v)){
int t=T.querymax(u,v);
if(T.val[t]>G[i].c){
T.cut(t,G[t-n].u);
T.cut(t,G[t-n].v);
}
else {
if(find()==find(n))_=min(_,G[i].w+T.val[T.querymax(,n)]);
continue;
}
}
else f[find(u)]=find(v);
T.val[n+i]=G[i].c;T.maxv[n+i]=n+i;
T.link(u,n+i);T.link(v,n+i);
if(find()==find(n))_=min(_,G[i].w+T.val[T.querymax(,n)]);
}
if(_==inf)puts("-1");else printf("%d\n",_);
return ;
}
4.uoj 共价大爷游长沙
%%%%毛爷爷,不看题解不会系列。
这题做的极其艰辛:
1.zcy:我怎么维护子树size啊…………啊………………
想了半个下午,我好像会了!去机房写!
2.zcy:我的权值怎么这么小啊,都是几十几十的东西……
wori,随机数种子选的有毒?我去uoj上找一个吧……
3.zcy:我的link怎么权值改的那么鬼啊?我看看……
wori,cut写错了,mdzz。
代码准确度啊……
#include<bits/stdc++.h>
#define N 300100
using namespace std;
int n,m,x,y,z;
struct Link_Cut_Tree{
int c[N][],q[N],fa[N],size[N],top,rev[N],val[N],sumv[N];
int a[N],b[N],w[N],sum;
inline bool isroot(int x){return fa[x]==||c[fa[x]][]!=x&&c[fa[x]][]!=x;}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
void pushall(int x){
if(!isroot(x))pushall(fa[x]);pushdown(x);
}
inline void pushup(int x){
sumv[x] = val[x]^sumv[c[x][]]^sumv[c[x][]];
}
void rotate(int x){
int y = fa[x],g=fa[y],ch=c[y][]==x;
if (!isroot(y))c[g][c[g][]==y]=x;
c[y][ch]=c[x][!ch],fa[c[y][ch]]=y;
fa[y] =x,fa[x]=g,c[x][!ch] = y;
pushup(y);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
pushup(x);
}
void access(int x){
for(int t=;x;t=x,x=fa[x]){
splay(x);val[x]^=sumv[t]^sumv[c[x][]];
c[x][]=t;pushup(x);
}
}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){
makeroot(x);makeroot(y);fa[x]=y;val[y]^=sumv[x];pushup(y);
}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){
makeroot(y);access(y);splay(x);fa[x]=;val[y]^=sumv[x];pushup(y);
}
void change(int x,int v){access(x);splay(x);val[x]^=v;pushup(x);}
}T; struct Edge{
int u;int v;int w;
Edge(int a=,int b=,int c=){u=a;v=b;w=c;}
}G[*N];
inline int read(){
int x=,f=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
int id;
id=read();n=read();m=read();
srand(time(NULL));
for(int i=;i<n;i++){
x=read(),y=read();
T.link(x,y);
}x=;y=;
int tot=,res=;
while(m--){
int opt=read(),x,y,u,v;
if(opt==){
x=read();y=read();u=read();v=read();
T.cut(x,y);T.link(u,v);//printf("%d\n",T.val[v]);
}
else if(opt==){
int k=rand();
x=read(),y=read();while(!k)k=rand();
G[++tot]=Edge(x,y,k);res^=k;
T.change(x,k);T.change(y,k);
//printf("%d\n",T.val[y]);
}
else if(opt==){
x=read();
res^=G[x].w;
T.change(G[x].u,G[x].w);T.change(G[x].v,G[x].w);
}
else if(opt==){
x=read();y=read();
T.makeroot(x);T.access(y);
if(T.val[y]==res)puts("YES");
else puts("NO");
}
//printf("%d\n",res);printf("%d\n",T.val[y]);
}
return ;
}
不开心,这个快把我写死的LCT居然只有100行
5.ZJOI2012 网络
这题如果单看每种颜色,我们只要建一个LCT就能轻松水过去,无非是要加个cnt
但是颜色多怎么办?考虑颜色种类很小,我们多建几个LCT不就行了么?
#include<bits/stdc++.h>
#define N 10005
#define M 100005
using namespace std;
int n, m, c, k, u, v, w, op, x,val[N];
struct Link_Cut_Tree{
int c[N][],fa[N],rev[N],maxv[N],cnt[N],q[N];
inline void pushup(int x){
maxv[x]=val[x];int l=c[x][],r=c[x][];
if(l)maxv[x]=max(maxv[x],maxv[l]);
if(r)maxv[x]=max(maxv[x],maxv[r]);
}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][])==x;r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){cnt[x]++;cnt[y]++;makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);cnt[x]--;cnt[y]--;c[y][]=fa[x]=;pushup(y);}
int find(int x){access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;}
int querymax(int x,int y){split(x,y);return maxv[y];}
}lct[];
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
struct Edge{
int u,v;
bool operator<(const Edge &x)const{if(u!=x.u)return u<x.u;
else return v<x.v;}
};
map<Edge,int> mp;
int main(){
n=read();m=read();c=read();k=read();
for(int i=;i<=n;i++)val[i]=read();
for(int i=;i<=m;i++){
int u=read(),v=read(),w=read();
w++;
Edge e1=(Edge){u,v},e2=(Edge){v,u};
mp[e1]=mp[e2]=w;
lct[w].link(u,v);
}
while(k--){
int opt=read();
if(opt==){
int x=read(),w=read();
val[x]=w;
for(int i=;i<=c;i++)lct[i].splay(x);
}
else if(opt==){
int u=read(),v=read(),w=read();
w++;
Edge a=(Edge){u,v},b=(Edge){v,u};
if(!mp.count(a)){
puts("No such edge.");continue;
}
int xxx=mp[a];
if(xxx==w){
puts("Success.");continue;
}
if(lct[w].cnt[u]>=||lct[w].cnt[v]>=){
puts("Error 1.");continue;
}
if(lct[w].find(u)==lct[w].find(v)){
puts("Error 2.");continue;
}
puts("Success.");
lct[xxx].cut(u,v);lct[w].link(u,v);
mp[a]=mp[b]=w;
}else{
int w=read(),u=read(),v=read();
w++;
if(lct[w].find(u)!=lct[w].find(v)){
puts("-1");continue;
}
printf("%d\n",lct[w].querymax(u,v));
}
}
return ;
}
【学习笔记】动态树Link-Cut-Tree的更多相关文章
- 动态树(Link Cut Tree) :SPOJ 375 Query on a tree
QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...
- 【学习笔记】LCT link cut tree
大概就是供自己复习的吧 1. 细节讲解 安利两篇blog: Menci 非常好的讲解与题单 2.模板 把 $ rev $ 和 $ pushdown $ 的位置记清 #define lc son[x][ ...
- 学习笔记-动态树Link-Cut-Tree
--少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
- 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)
题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...
- LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板
P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- LG3690 【模板】Link Cut Tree (动态树)
题意 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的 ...
随机推荐
- BZOJ3124 SDOI2013直径
本以为必有高论,结果是个思博题.随便找一条直径,最后答案肯定是这条直径上的连续一段,如果某分支长度等于直径上某端的长度这一端都要被剪掉. #include<iostream> #inclu ...
- BZOJ4804 欧拉心算(莫比乌斯反演+欧拉函数+线性筛)
一通套路后得Σφ(d)μ(D/d)⌊n/D⌋2.显然整除分块,问题在于怎么快速计算φ和μ的狄利克雷卷积.积性函数的卷积还是积性函数,那么线性筛即可.因为μ(pc)=0 (c>=2),所以f(pc ...
- Oracle DB_LINK如何使用
语句,或可通过可视化操作 -- Create database link create database link DBL_TESTconnect to UID identified by PSWus ...
- [洛谷P4735]最大异或和
题目大意:有一串初始长度为$n$的序列$a$,有两种操作: $A\;x:$在序列末尾加一个数$x$ $Q\;l\;r\;x:$找一个位置$p$,满足$l\leqslant p\leqslant r$, ...
- BZOJ3653 & 洛谷3899:谈笑风生——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3653 https://www.luogu.org/problemnew/show/P3899 设 ...
- 洛谷3805:【模板】manacher算法——题解
https://www.luogu.org/problemnew/show/P3805 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 板子题, ...
- [Leetcode] pascals triangle ii 帕斯卡三角
Given an index k, return the k th row of the Pascal's triangle. For example, given k = 3,Return[1,3, ...
- C/C++中二维数组和指针关系分析
在C/c++中,数组和指针有着密切的关系,有很多地方说数组就是指针式错误的一种说法.这两者是不同的数据结构.其实,在C/c++中没有所谓的二维数组,书面表达就是数组的数组.我猜想是为了表述方便才叫它二 ...
- UVALive - 5713 最小生成树
题意: 秦始皇修路,已知n个城市的坐标以及该城市的人口数,修路的费用是两个城市之间的欧几里得距离,其中可以有一条路不用花费代价但是要求这条路连接的两个城市的人口之和A/B尽量大,其中B是修路的总费用. ...
- c# MD5盐值加密
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptograph ...