dash -> bash

ubuntu下/bin/sh的指向
 
ubuntu 下 /bin/sh 默认是dash,用ll /bin/sh就可以看出来sh是指向dash的链接,有时候会导致使用bash脚本的时候出问题。
 
如果遇到这个问题了,就要把sh指向bash。
 
可以用ln:ln -s /bin/bash /bin/sh
/** * implement a container like std::map */ #ifndef SJTU_MAP_HPP #define SJTU_MAP_HPP #include <cstdio> // only for std::less<T> #include <functional> #include <cstddef> #include "utility.hpp" #include "exceptions.hpp" namespace sjtu { template< class Key, class T, class Compare = std::less <Key> > class AAtree{ public: typedef pair<const Key, T> value_type; struct Node { Node *lson, *rson, *parent; int level; value_type data; Node(const value_type &d, int lv = 1, Node *p = nullptr, Node *l = nullptr, Node *r = nullptr) : data(d), level(lv), parent(p), lson(l), rson(r) {} }; Node *root; size_t tree_size; Compare comp; AAtree(): root(nullptr), tree_size(0) {} AAtree(const AAtree &other) { root = copyTree(other.root, nullptr); tree_size = other.tree_size; } AAtree &operator=(const AAtree &other) { if (this != &other) { clear(root); root = copyTree(other.root, nullptr); tree_size = other.tree_size; } return *this; } ~AAtree() { clear(root); tree_size = 0; } Node *skew(Node *node) { if (!node || !node->lson) return node; if (node->lson->level == node->level) { Node *L = node->lson; node->lson = L->rson; if (L->rson) L->rson->parent = node; L->rson = node; L->parent = node->parent; node->parent = L; return L; } return node; } Node *split(Node *node) { if (!node || !node->rson || !node->rson->rson) return node; if (node->level == node->rson->rson->level) { Node *R = node->rson; node->rson = R->lson; if (R->lson) R->lson->parent = node; R->lson = node; R->parent = node->parent; node->parent = R; ++R->level; return R; } return node; } Node *insert(Node *node, const value_type &value, Node *parent = nullptr) { if (!node) { ++tree_size; return new Node(value, 1, parent); } if (comp(value.first, node->data.first)) { node->lson = insert(node->lson, value, node); node->lson->parent = node; } else if (comp(node->data.first, value.first)) { node->rson = insert(node->rson, value, node); node->rson->parent = node; } else return node; node = skew(node); node = split(node); return node; } Node *erase(Node *node, const Key &key) { if (!node) return nullptr; if (comp(key, node->data.first)) { node->lson = erase(node->lson, key); if (node->lson) node->lson->parent = node; } else if (comp(node->data.first, key)) { node->rson = erase(node->rson, key); if (node->rson) node->rson->parent = node; } else { if (!node->lson && !node->rson) { if (node->parent) { if (node->parent->lson == node) { node->parent->lson = nullptr; } else { node->parent->rson = nullptr; } } delete node; node = nullptr; --tree_size; return nullptr; } else if (!node->lson) { Node *temp = node->rson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } else if (!node->rson) { Node *temp = node->lson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } Node *predecessor = node->lson; while (predecessor->rson) predecessor = predecessor->rson; Node *newNode = new Node(predecessor->data, node->level, node->parent, node->lson, node->rson); if (newNode->lson) newNode->lson->parent = newNode; if (newNode->rson) newNode->rson->parent = newNode; if (newNode->parent) { if (newNode->parent->lson == node) { newNode->parent->lson = newNode; } else { newNode->parent->rson = newNode; } } newNode->lson = erase(newNode->lson, predecessor->data.first); if (newNode->lson) newNode->lson->parent = newNode; delete node; node = newNode; } if (node->lson && node->rson) { size_t min_level = node->lson->level < node->rson->level ? node->lson->level : node->rson->level; if (node->level > min_level + 1) { node->level = min_level + 1; if (node->rson && node->rson->level > node->level) node->rson->level = node->level; } } node = skew(node); node->rson = skew(node->rson); if (node->rson) node->rson->rson = skew(node->rson->rson); node = split(node); node->rson = split(node->rson); return node; } Node *find(Node *node, const Key &key) const { while (node) { if (comp(key, node->data.first)) node = node->lson; else if (comp(node->data.first, key)) node = node->rson; else return node; } return nullptr; } Node *findMin(Node *node) const { if (!node) return nullptr; // printf("In findmin: %d\n", (node)); while (node->lson) node = node->lson; // printf("finish find min\n"); return node; } Node *findMax(Node *node) const { if (!node) return nullptr; while (node->rson) node = node->rson; return node; } Node *successor(Node *node) const { // printf("in successor\n"); if (!node) return nullptr; // printf("in successor2\n"); if (node->rson) return findMin(node->rson); // printf("in successor3\n"); Node *parent = node->parent; while (parent && node == parent->rson) { node = parent; parent = parent->parent; } // printf("finish successor\n"); return parent; } Node *predecessor(Node *node) const { if (!node) return nullptr; if (node->lson) return findMax(node->lson); Node *parent = node->parent; while (parent && node == parent->lson) { node = parent; parent = parent->parent; } return parent; } Node *copyTree(Node *node, Node *parent) { if (!node) return nullptr; Node *newNode = new Node(node->data, node->level, parent); newNode->lson = copyTree(node->lson, newNode); newNode->rson = copyTree(node->rson, newNode); return newNode; } void clear(Node *node) { if (!node) return; clear(node->lson); clear(node->rson); delete node; node = nullptr; } }; template< class Key, class T, class Compare = std::less <Key> > class map { public: /** * the internal type of data. * it should have a default constructor, a copy constructor. * You can use sjtu::map as value_type by typedef. */ typedef pair<const Key, T> value_type; AAtree<Key, T, Compare> aa_tree; /** * see BidirectionalIterator at CppReference for help. * * if there is anything wrong throw invalid_iterator. * like it = map.begin(); --it; * or it = map.end(); ++end(); */ typedef typename AAtree<Key, T, Compare>::Node Node; class const_iterator; class iterator { private: /** * TODO add data members * just add whatever you want. */ map* container; Node *node; public: iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } iterator(const iterator &other):container(other.container), node(other.node) { // TODO } /** * TODO iter++ */ iterator operator++(int) { if (!node) throw invalid_iterator(); iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ iterator operator--(int) { iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.node && container == rhs.container; } bool operator==(const const_iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.node || container != rhs.container; } bool operator!=(const const_iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; class const_iterator { // it should has similar member method as iterator. // and it should be able to construct from an iterator. private: // data members. map* container; Node *node; public: // const_iterator(const map *c = nullptr, Node *n = nullptr): container(const_cast<map*>(c)), node(n) { // // TODO // } const_iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } const_iterator(const const_iterator &other): container(other.container), node(other.node) { // TODO } const_iterator(const iterator &other) { // TODO container = other.getContainer(); node = other.getNode(); } /** * TODO iter++ */ const_iterator operator++(int) { if (!node) throw invalid_iterator(); const_iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ const_iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ const_iterator operator--(int) { const_iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ const_iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ const value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } bool operator==(const const_iterator &rhs) const { return node == rhs.node && container == rhs.container; } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } bool operator!=(const const_iterator &rhs) const { return node != rhs.node || container != rhs.container; } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ const value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; /** * TODO two constructors */ map(): aa_tree() {} map(const map &other): aa_tree(other.aa_tree) {} /** * TODO assignment operator */ map &operator=(const map &other) { if (this != &other) { aa_tree = other.aa_tree; } return *this; } /** * TODO Destructors */ ~map() {} /** * TODO * access specified element with bounds checking * Returns a reference to the mapped value of the element with key equivalent to key. * If no such element exists, an exception of type `index_out_of_bound' */ T &at(const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } const T &at(const Key &key) const { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } /** * TODO * access specified element * Returns a reference to the value that is mapped to a key equivalent to key, * performing an insertion if such key does not already exist. */ T &operator[](const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (node) return node->data.second; aa_tree.root = aa_tree.insert(aa_tree.root, value_type(key, T())); return aa_tree.find(aa_tree.root, key)->data.second; } /** * behave like at() throw index_out_of_bound if such key does not exist. */ const T &operator[](const Key &key) const { return at(key); } /** * return a iterator to the beginning */ iterator begin() { return iterator(this, aa_tree.findMin(aa_tree.root)); } const_iterator cbegin() const { return const_iterator(const_cast<map*>(this), aa_tree.findMin(aa_tree.root)); } /** * return a iterator to the end * in fact, it returns past-the-end. */ iterator end() { return iterator(this, nullptr); } const_iterator cend() const { return const_iterator(const_cast<map*>(this), nullptr); } /** * checks whether the container is empty * return true if empty, otherwise false. */ bool empty() const { return aa_tree.tree_size == 0; } /** * returns the number of elements. */ size_t size() const { return aa_tree.tree_size; } /** * clears the contents */ void clear() { aa_tree.clear(aa_tree.root); aa_tree.root = nullptr; aa_tree.tree_size = 0; } /** * insert an element. * return a pair, the first of the pair is * the iterator to the new element (or the element that prevented the insertion), * the second one is true if insert successfully, or false. */ pair<iterator, bool> insert(const value_type &value) { auto node = aa_tree.find(aa_tree.root, value.first); if (node) return {iterator(this, node), false}; aa_tree.root = aa_tree.insert(aa_tree.root, value); node = aa_tree.find(aa_tree.root, value.first); return {iterator(this, node), true}; } /** * erase the element at pos. * * throw if pos pointed to a bad element (pos == this->end() || pos points an element out of this) */ void erase(iterator pos) { if (pos == end() || pos.getContainer() != this) throw invalid_iterator(); aa_tree.root = aa_tree.erase(aa_tree.root, (*pos).first); } /** * Returns the number of elements with key * that compares equivalent to the specified argument, * which is either 1 or 0 * since this container does not allow duplicates. * The default method of check the equivalence is !(a < b || b > a) */ size_t count(const Key &key) const { return aa_tree.find(aa_tree.root, key) ? 1 : 0; } /** * Finds an element with key equivalent to key. * key value of the element to search for. * Iterator to an element with key equivalent to key. * If no such element is found, past-the-end (see end()) iterator is returned. */ iterator find(const Key &key) { return iterator(this, aa_tree.find(aa_tree.root, key)); } const_iterator find(const Key &key) const { return const_iterator(const_cast<map*>(this), aa_tree.find(aa_tree.root, key)); } }; } #endif 下面是valgrind的报错: ==9160== Invalid read of size 4 ==9160== at 0x10FDB9: check13() (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x110CC9: main (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== Address 0x6c8bcfc is 28 bytes inside a block of size 40 free'd ==9160== at 0x484BB6F: operator delete(void*, unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==9160== by 0x1150A1: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115292: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x114F98: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== Block was alloc'd at ==9160== at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==9160== by 0x1147E3: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x114850: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x114850: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x1148A7: sjtu::AAtree<int, int, std::less<int> >::insert(sjtu::AAtree<int, int, std::less<int> >::Node*, sjtu::pair<int const, int> const&, sjtu::AAtree<int, int, std::less<int> >::Node*) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== Test 13 Passed! Test 14 Passed! ==9160== ==9160== HEAP SUMMARY: ==9160== in use at exit: 0 bytes in 0 blocks ==9160== total heap usage: 325,886 allocs, 325,886 frees, 13,111,520 bytes allocated ==9160== ==9160== All heap blocks were freed -- no leaks are possible ==9160== ==9160== ERROR SUMMARY: 4308 errors from 1 contexts (suppressed: 0 from 0) ==9160== ==9160== 4308 errors in context 1 of 1: ==9160== Invalid read of size 4 ==9160== at 0x10FDB9: check13() (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x110CC9: main (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== Address 0x6c8bcfc is 28 bytes inside a block of size 40 free'd ==9160== at 0x484BB6F: operator delete(void*, unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==9160== by 0x1150A1: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) ==9160== by 0x115001: sjtu::AAtree<int, int, std::less<int> >::erase(sjtu::AAtree<int, int, std::less<int> >::Node*, int const&) (in /root/code/STLite/STLite-ACM-2025/map/build/map_three_men) map_three_men: bool check13(){ // erase(it--) sjtu::map<int, int> Q; std::map<int, int> stdQ; int num[30001]; num[0] = 0; for(int i = 1; i <= 30000; i++) num[i] = num[i - 1] + rand() % 325 + 1; for(int i = 1; i <= 60000; i++) swap(num[rand() % 30000 + 1], num[rand() % 30000 + 1]); for(int i = 1; i <= 30000; i++){ int t = rand(); stdQ[num[i]] = t; Q[num[i]] = t; } // cout << "Stage 1" << endl; sjtu::map<int, int>::iterator it; std::map<int, int>::iterator stdit; for(int i = 1; i <= 60000; i++) swap(num[rand() % 30000 + 1], num[rand() % 30000 + 1]); for(int i = 1; i <= 10325; i++){ it = Q.find(num[i]); if(it != Q.begin()) { Q.erase(it--); // cout << "Erase it" << endl; } stdit = stdQ.find(num[i]); if(stdit != stdQ.begin()) { stdQ.erase(stdit--); // cout << "Erase it" << endl; } // cout << "i = " << i << " it, std = " << (it)->first << " " << stdit->first << endl; if(it -> first != stdit -> first)return 0; } // cout << "Stage 2" << endl; if(Q.size() != stdQ.size()) return 0; it = Q.begin(); // cout << "Stage 3" << endl; for(stdit = stdQ.begin(); stdit != stdQ.end(); stdit++){ if(stdit -> first != it -> first) return 0; if(stdit -> second != (*it).second) return 0; it++; } stdit = --stdQ.end(); for(it = --Q.end(); it != Q.begin(); it--){ if(stdit -> first != it -> first) return 0; if(stdit -> second != (*it).second) return 0; stdit--; } return 1; }
最新发布
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值