zoukankan      html  css  js  c++  java
  • 神奇的结构体

    在篇头,首先需要感谢的就是给予作者指导的神 ( ext{JacderZhang}) ,感谢。

    引子

    有一天,作者在虚树板子题的时候突然犯懒了,想利用一个结构同时维护两种树的信息,其中一种树我需要有倍增,而另外一种树我不需要,于是我突发奇想可不可以搞一个结构体,然后我可以选择是否开出我倍增需要的空间,从而起到优化空间和代码复杂度的问题(实际上并没有优化代码复杂度)。

    然后我写出了这样的一段代码:

    struct Tree{
        struct Node{int dep;}tr[N];
        Tree(){memset(tr,0,sizeof(tr));}
        struct Edge{int nxt,to,val;}e[N<<1];int fir[N];
        void add(int u,int v,int w,int i){e[i]=(Edge){fir[u],v,w},fir[u]=i;}
        struct Beizeng{
            int fa[N][20],data[N][20];
            void init(){
                for(int i=1;i<20;++i){
                    for(int j=1;j<=n;++j){
                        fa[j][i]=fa[fa[j][i-1]][i-1];
                        data[j][i]=min(data[j][i-1],data[fa[j][i-1]][i-1]);
                    }
                }
            }
            void lca(int u,int v){
                if(tr[u].dep<tr[v].dep) swap(u,v);
                /*....*/
            }
        };
    }t,now;
    

    写到这里的时候,作者的 ( ext{vscode}) 就给我疯狂报错,说什么非静态成员引用必须与特定对象相对,错误是在函数 ( ext{lca}) 中的 ( ext{tr}) ,然后我就很迷惑,就上网 ( ext{google}) 了一下,意识到了问题的关键。

    他报错的原因是因为我在结构体里面的函数调用的 tr 是一个不确定的变量,里面的结构体 Beizeng 无法得知他外面的所套的 Tree 到底是哪一个,所以针对这个问题,我们就可以有了一个解决方案。

    我们可以在 Beizeng 里面开一个指针,然后在定义的时候就将这个指针 Tr 指向外面的 Tree 就可以直接调用了。

    然后这个问题就解决了,但是我想要的空间复杂度上的优化并没有实现。

    进阶

    然后发现,我们实际上可以开两个结构体,相应的要不要写倍增,给倍增开空间就可以解决了,但是这样的话外面就需要写两棵树,没有达到代码复杂度降低的目的。

    然后我们就可以引入一个叫做继承的概念。就是一个子类可以继承父类的特性,同时可以满足拥有自己的特性,写下来大致是这样。

    struct TreeBase {
    	struct Node{int dep;}tr[N];
    	struct Edge{int nxt,to,val;}e[N<<1];int fir[N];
    	void add(int u,int v,int w,int i){e[i]=(Edge){fir[u],v,w},fir[u]=i;}
    };
    struct TreeWithBeizeng:virtual public TreeBase {
    	int fa[N][20],data[N][20];
    	void init(){
    		for(int i=1;i<20;++i){
    			for(int j=1;j<=n;++j){
    				fa[j][i]=fa[fa[j][i-1]][i-1];
    				data[j][i]=min(data[j][i-1],data[fa[j][i-1]][i-1]);
    			}
    		}
    	}
    	void lca(int u,int v){
    		if(tr[u].dep < tr[v].dep) swap(u,v);
    	}
    };
    

    其中继承有三个参数:

    • 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有保护成员来访问。
    • 保护继承(protected): 当一个类派生自保护基类时,基类的公有保护成员将成为派生类的保护成员。
    • 私有继承(private):当一个类派生自私有基类时,基类的公有保护成员将成为派生类的私有成员。

    然后其中的 virtual 实际上是一种判重机制,就是如果一个类继承了多次同一个类,写了 virtual 的类会被只记录一次。

    具体的可以去这里学习一下。

    然后我们这里就是利用这个继承的特性,然后对应需要的树就开对应的结构体,然后同时节约了空间且简短了代码。

    我突然觉得这个博客有点蠢看起来。

    拓展

    同时的是,作者还在其中学习了关于构造函数的一些问题。

    比如我们的初始化 a=1 实际上他是这样的 a(1)

    这就是为什么 const int a=1; 是可行的,但是 const int a;a=1; 是不可行的了。

    因为实际上 const 类型是只接受构造函数的修改的。

    然后对于构造函数,他也有两种写法

    struct PK_is_a_Fool{
    	const int IQ;
    	PK_is_a_Fool(int a):IQ(a){}
    	PK_is_a_Fool(int a){IQ=a;}
    };
    

    但是两者是有区别的,区别和 const 对于两者的区别一样但是注意,第一种不能这么写

    struct PK_is_a_Fool{
    	const int IQ;
    	PK_is_a_Fool(int a){IQ(a);}
    };
    

    这个是错的。

    果然这个博客很傻逼,写得都是别人知道的东西。

    神的代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+5;
    int n;
    
    struct TreeBase {
    	struct Node{int dep;}tr[N];
    	struct Edge{int nxt,to,val;}e[N<<1];int fir[N];
    	void add(int u,int v,int w,int i){e[i]=(Edge){fir[u],v,w},fir[u]=i;}
    };
    
    struct TreeWithBeizeng : virtual public TreeBase {
    	int fa[N][20],data[N][20];
    	void init(){
    		for(int i=1;i<20;++i){
    			for(int j=1;j<=n;++j){
    				fa[j][i]=fa[fa[j][i-1]][i-1];
    				data[j][i]=min(data[j][i-1],data[fa[j][i-1]][i-1]);
    			}
    		}
    	}
    	void lca(int u,int v){
    		if(tr[u].dep < tr[v].dep) swap(u,v);
    	}
    };
    
    struct TreeWithSP : virtual public TreeBase {
    	/* ... */
    	/*
    	struct Foo : public bar;
    	int a : 2;
    	Foo(int a) : a(a);
    	int a = flag ? 1 : 0; 
    	for (int v: e[u]) {	}
    	for (auto v_iterator = e[u].begin(), v; _iterator != e[u].end(); ++v_iterator) {
    		v = *v_iterator;
    	}
    	*/
    	int weight_son[N];
    	void modify(int u, int v) {
    		printf("modify(%d, %d)
    ", u, v);
    	}
    };
    
    struct Tree : public TreeBase, public TreeWithBeizeng, public TreeWithSP {}
    t,now;
    
    int main(){
    	t.modify(1,2);
    	t.init();
    	t.lca(1,2);
    }
    
  • 相关阅读:
    SQL语句导入导出大全
    数据库连接大全
    数据库关键字过滤问题
    HttpHandler
    asp代码的一个do。。。wile循环代码
    vs .net 2005 的Global.asax 在哪添加
    asp.net项目ckeditor+ckfinder实现图片上传
    CKEditor+CKFinder的图片上传配置
    asp实现统计访问量的代码
    asp.net绘统计图
  • 原文地址:https://www.cnblogs.com/Point-King/p/14593618.html
Copyright © 2011-2022 走看看