• 线段树


    题目是从傻崽博客里拉来的,自己写的代码。

    1.hdu1166 敌兵布阵
    更新节点,区间求和。一次AC,做的时候也没遇见什么问题!

    View Code
    #include <iostream>
    #include
    <string>
    using namespace std;
    #define MAX_N 50000

    string str;
    int sum; //记录总兵数
    int num[MAX_N+1]={0}; //记录各个兵营的兵数

    typedef
    struct node
    {
    int left;
    int right;
    int data;
    node
    * lchild;
    node
    * rchild;
    node()
    {
    left
    = right = data = 0;
    }
    }Tree;

    Tree
    * CreateTree(int a,int b)
    {
    Tree
    * r;
    r
    = (Tree*)malloc(sizeof(Tree));

    r
    ->left = a;
    r
    ->right = b;
    if(a == b)
    {
    r
    ->data = num[a];
    r
    ->lchild = r->rchild = NULL;
    }
    else
    {
    int mid = (a+b)>>1;
    r
    ->lchild = CreateTree(a,mid);
    r
    ->rchild = CreateTree(mid+1,b);
    r
    ->data = r->lchild->data + r->rchild->data;
    }

    return r;
    }

    void insert(Tree* r,int a,int b)
    {
    if(r->left == a && r->right == a)
    {
    r
    ->data += b;
    return;
    }
    int mid = (r->left + r->right)>>1;
    if(a <= mid)
    {
    insert(r
    ->lchild,a,b);
    }
    else
    {
    insert(r
    ->rchild,a,b);
    }
    r
    ->data += b;
    }

    void find(Tree* r,int a,int b)
    {
    if(r->left == a && r->right == b)
    {
    sum
    += r->data;
    return;
    }
    int mid = (r->left + r->right)>>1;
    if(b<=mid)
    {
    find(r
    ->lchild,a,b);
    }
    else if(a>mid)
    {
    find(r
    ->rchild,a,b);
    }
    else
    {
    find(r
    ->lchild,a,mid);
    find(r
    ->rchild,mid+1,b);
    }
    }

    int main()
    {
    int t,n,x,y;
    int i;
    int ca = 0;
    scanf(
    "%d",&t);
    while(t--)
    {
    printf(
    "Case %d:\n",++ca);
    scanf(
    "%d",&n);
    for(i=1;i<=n;i++)
    {
    scanf(
    "%d",&num[i]);
    }
    Tree
    * T;
    T
    = CreateTree(1,n);
    while(cin>>str)
    {
    if(str == "Query")
    {
    sum
    = 0;
    scanf(
    "%d%d",&x,&y);
    find(T,x,y);
    printf(
    "%d\n",sum);
    }
    else if(str == "Add")
    {
    scanf(
    "%d%d",&x,&y);
    insert(T,x,y);
    }
    else if(str == "Sub")
    {
    scanf(
    "%d%d",&x,&y);
    insert(T,x,
    -y);
    }
    else
    {
    break;
    }
    }
    }
    return 0;
    }

    2.hdu1754 I Hate It
    更新节点,区间最值。一开始用链表建树,发现MLE了,就改成了数组建树,过!

    View Code
    #include <iostream>
    using namespace std;

    #define MAX_N 200000

    int big;
    typedef
    struct node
    {
    int left;
    int right;
    int data;
    int maxx;
    }node;

    node stu[MAX_N
    *4];
    //int num[MAX_N+1];

    int Max(int a,int b)
    {
    return a>b?a:b;
    }

    void CreateTree(int ii,int a,int b)
    {
    stu[ii].left
    = a;
    stu[ii].right
    = b;
    stu[ii].maxx
    = 0;
    stu[ii].data
    = 0;
    if(a == b)
    {
    return;
    }
    else
    {
    int mid = (a+b)>>1;
    CreateTree(ii
    *2,a,mid);
    CreateTree(ii
    *2+1,mid+1,b);
    }
    }

    void updata(int ii,int a,int b)
    {
    if(stu[ii].left == a && stu[ii].right == a)
    {
    stu[ii].data
    = b;
    stu[ii].maxx
    = b;
    }
    else
    {
    int mid = (stu[ii].left+stu[ii].right)>>1;
    if(a <= mid)
    {
    updata(ii
    *2,a,b);
    }
    else
    {
    updata(ii
    *2+1,a,b);
    }
    if(b > stu[ii].maxx)
    stu[ii].maxx
    = b;
    }
    }

    void find(int ii,int a,int b)
    {
    if(stu[ii].left == a && stu[ii].right == b)
    {
    //printf("%d\n",stu[ii].maxx);
    if(stu[ii].maxx > big)
    big
    = stu[ii].maxx;
    }
    else
    {
    int mid = (stu[ii].left + stu[ii].right)>>1;
    if(b <= mid)
    {
    find(ii
    *2,a,b);
    }
    else if(a > mid)
    {
    find(ii
    *2+1,a,b);
    }
    else
    {
    find(ii
    *2,a,mid);
    find(ii
    *2+1,mid+1,b);
    }
    }
    }

    int main()
    {
    int n,m,num;
    int i;

    while(scanf("%d%d",&n,&m)!=EOF)
    {
    CreateTree(
    1,1,n);
    for(i=1;i<=n;i++)
    {
    scanf(
    "%d",&num);
    updata(
    1,i,num);
    }
    char c;
    int x1,x2;
    while(m--)
    {
    scanf(
    "%*c%c",&c);
    scanf(
    "%d%d",&x1,&x2);
    if(c == 'Q')
    {
    big
    = 0x80000000;
    find(
    1,x1,x2);
    printf(
    "%d\n",big);
    }
    else
    {
    updata(
    1,x1,x2);
    }
    }
    }
    return 0;
    }
    3.hdu1698 Just a Hook
    成段更新,总区间求和.也不是很难,注意递归时一层一层的递归下去。写的时候中间忽略了一点,造成错了好几次!

    View Code
    #include <iostream>
    using namespace std;
    #define MAX_N 100000

    struct node
    {
    int left;
    int right;
    int data;
    int sum;
    };
    node hook[
    4*MAX_N];

    void CreateTree(int ii,int a,int b)
    {
    hook[ii].left
    = a;
    hook[ii].right
    = b;
    if(a == b)
    {
    hook[ii].data
    = 1;
    hook[ii].sum
    = 1;
    }
    else
    {
    int mid = (a+b)>>1;
    CreateTree(ii
    *2,a,mid);
    CreateTree(ii
    *2+1,mid+1,b);
    hook[ii].data
    = 0;
    hook[ii].sum
    = (hook[ii*2].sum + hook[ii*2+1].sum);
    }
    }

    void updata(int ii,int a,int b,int c)
    {
    if(hook[ii].left == a && hook[ii].right == b)
    {
    hook[ii].data
    = c;
    hook[ii].sum
    = (b-a+1)*c;
    }
    else
    {
    if(hook[ii].data > 0)
    {
    hook[ii
    *2].data = hook[ii].data;
    hook[ii
    *2].sum = (hook[ii*2].right - hook[ii*2].left+1)*hook[ii*2].data;
    hook[ii
    *2+1].data = hook[ii].data;
    hook[ii
    *2+1].sum = (hook[ii*2+1].right - hook[ii*2+1].left+1)*hook[ii*2+1].data;
    }
    hook[ii].data
    = 0; //写的时候这个丢掉了。一直错
    int mid = (hook[ii].left + hook[ii].right)>>1;
    if(b <= mid)
    {
    updata(ii
    *2,a,b,c);
    }
    else if(a > mid)
    {
    updata(ii
    *2+1,a,b,c);
    }
    else
    {
    updata(ii
    *2,a,mid,c);
    updata(ii
    *2+1,mid+1,b,c);
    }
    hook[ii].sum
    = hook[ii*2].sum + hook[ii*2+1].sum;
    }
    }


    int main()
    {
    int t,n,m,x1,x2,x3;
    int i;
    scanf(
    "%d",&t);
    for(i=1;i<=t;i++)
    {
    scanf(
    "%d",&n);
    CreateTree(
    1,1,n);
    scanf(
    "%d",&m);
    while(m--)
    {
    scanf(
    "%d%d%d",&x1,&x2,&x3);
    updata(
    1,x1,x2,x3);
    }
    printf(
    "Case %d: The total value of the hook is %d.\n",i,hook[1].sum);
    }
    return 0;
    }

    4.hdu1394 Minimum Inversion Number
    更新节点,区间求和(实现nlog(n)的逆序数方法,和树状数组比起来实在是有点鸡肋)

    .
    5.hdu1779 9-Problem C暂不公开
    成段更新,区间最值

    .
    6.pku2777 Count Color
    成段更新,区间统计,位运算加速(我总把query里的传递给子节点的步骤忘了)。错了蛮多次的,一开始是RE,应该是中间跑的时候循环有问题,后来的话WA,find函数中存在问题!

    View Code
    #include <iostream>
    #include
    <algorithm>
    using namespace std;
    #define MAX_N 100000

    int t;
    int num[35];

    typedef
    struct node
    {
    int left;
    int right;
    int data;
    node
    * lchild;
    node
    * rchild;
    }Tree;

    Tree
    * CreateTree(int a,int b)
    {
    Tree
    * r;

    r
    =(Tree*)malloc(sizeof(Tree));
    r
    ->left = a;
    r
    ->right = b;
    r
    ->data = 1;

    if(a+1==b)
    r
    ->lchild=r->rchild=NULL;
    else
    {
    int mid = (a+b)>>1;
    r
    ->lchild = CreateTree(a,mid);
    r
    ->rchild = CreateTree(mid,b);
    }

    return r;
    }

    void search(Tree* r,int a,int b,int c)
    {
    //if(r->data == c)
    // return;
    if(r==NULL)
    return ;
    if(r->left == a && r->right == b)
    {
    r
    ->data = c;
    }
    else
    {
    if(r->data > 0)
    {
    r
    ->lchild->data=r->data;
    r
    ->rchild->data=r->data;
    }
    r
    ->data = 0;
    int mid = (r->left + r->right)>>1;
    if(a >= mid)
    {
    search(r
    ->rchild,a,b,c);
    }
    else if(b <= mid)
    {

    search(r
    ->lchild,a,b,c);
    }
    else
    {

    search(r
    ->lchild,a,mid,c);
    search(r
    ->rchild,mid,b,c);
    }

    //if(r->lchild->data == r->rchild->data)
    // {
    // r->data = r->lchild->data;
    // }
    }
    }

    void find(Tree* r,int a,int b)
    {
    /*if(r->left == a && r->right == b)
    {
    if(r->data > 0)
    {

    //num[r->data][0]++;
    if(num[r->data][0] == 0)
    {
    num[r->data][0]++;
    num[r->data][1] = r->right;
    }
    else
    {
    if(num[r->data][1] == r->left)
    num[r->data][1] = r->right;
    else
    {
    num[r->data][0]++;
    num[r->data][1] = r->right;
    }
    }
    }
    else if(r->data == 0)
    {
    int mid = (a+b)>>1;
    find(r->lchild,a,mid);
    find(r->rchild,mid,b);
    }
    return;
    }
    */
    if(r==NULL)
    return ;
    if(r->data > 0)
    {
    num[r
    ->data]++;
    return;
    }

    int mid = (r->left + r->right)>>1;
    if(a >= mid)
    {

    find(r
    ->rchild,a,b);
    }
    else if(b <= mid)
    {
    find(r
    ->lchild,a,b);
    }
    else
    {
    find(r
    ->lchild,a,mid);
    find(r
    ->rchild,mid,b);
    }
    }

    int Sum()
    {
    int i;
    int sum = 0;
    for(i=1;i<=t;i++)
    {
    if(num[i] != 0)
    sum
    ++;
    }
    return sum;
    }

    int main()
    {
    int l,m;

    while(scanf("%d%d%d",&l,&t,&m)!=EOF)
    {
    Tree
    * T;
    T
    = CreateTree(1,l+1);
    while(m--)
    {
    int x1,x2,color;
    char c;
    cin
    >>c;
    if(c == 'C')
    {
    scanf(
    "%d%d%d",&x1,&x2,&color);
    if(x1>x2)
    swap(x1,x2);
    search(T,x1,x2
    +1,color);
    }
    else
    {
    memset(num,
    0,sizeof(num));
    scanf(
    "%d%d",&x1,&x2);
    if(x1>x2)
    swap(x1,x2);
    find(T,x1,x2
    +1);
    printf(
    "%d\n",Sum());
    }
    }
    }
    return 0;
    }

    7.pku3468 A Simple Problem with Integers
    成段更新,区间求和(中间乘法会超int..纠结了)

    这题int因为一开始就注意,没出什么问题。但错了很多次,在成段更新的时候不能更新到点,这样肯定对超时的。这题是要加一个增量,表示该节点增加了多少。现在也不是很明白。线段树觉的重要的就是node中那些个域!

    View Code
    #include <iostream>
    using namespace std;
    #define MAX_N 100000

    __int64 sum
    = 0;
    __int64 num[MAX_N
    +1];

    struct node
    {
    int left;
    int right;
    __int64 count;
    //表示该节点的总个数
    __int64 data; //表示增量的那个数
    };

    node N[
    4*MAX_N];

    void CreateTree(int ini,int a,int b)
    {
    N[ini].left
    = a;
    N[ini].right
    = b;
    N[ini].data
    = 0;
    if(a == b)
    {
    N[ini].count
    = num[a];
    }
    else
    {
    int mid = (a+b) >> 1;
    if(b <= mid)
    CreateTree(ini
    *2,a,b);
    else if(a > mid)
    CreateTree(ini
    *2+1,a,b);
    else
    {
    CreateTree(ini
    *2,a,mid);
    CreateTree(ini
    *2+1,mid+1,b);
    }
    N[ini].count
    = N[ini*2].count+ N[ini*2+1].count;
    }
    }

    void insert(int ini,int a,int b,int c)
    {
    if(N[ini].left == a && N[ini].right == b)
    {
    N[ini].data
    += c;
    //N[ini].count+= (b-a+1) * c;
    }
    else
    {
    int mid = (N[ini].left + N[ini].right) >> 1;
    if(b <= mid)
    insert(ini
    *2,a,b,c);
    else if(a > mid)
    insert(ini
    *2+1,a,b,c);
    else
    {
    insert(ini
    *2,a,mid,c);
    insert(ini
    *2+1,mid+1,b,c);
    }
    N[ini].count
    = (N[ini*2].count + (N[ini*2].right - N[ini*2].left + 1) * N[ini*2].data)
    + (N[ini*2+1].count + (N[ini*2+1].right - N[ini*2+1].left + 1) * N[ini*2+1].data);
    }
    }

    void find(int ini,int a,int b)
    {
    if(N[ini].left == a && N[ini].right == b)
    {
    sum
    += N[ini].count + N[ini].data*(b-a+1);
    }
    else
    {
    N[ini
    *2].data += N[ini].data;
    N[ini
    *2+1].data += N[ini].data;
    N[ini].count
    += N[ini].data * (N[ini].right - N[ini].left + 1);
    N[ini].data
    = 0;
    int mid = (N[ini].left + N[ini].right) >> 1;
    if(b <= mid)
    find(ini
    *2,a,b);
    else if(a > mid)
    find(ini
    *2+1,a,b);
    else
    {
    find(ini
    *2,a,mid);
    find(ini
    *2+1,mid+1,b);
    }
    }
    }

    void Init()
    {
    int n,m,x1,x2,x3;
    char c;
    int i;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
    for(i=1;i<=n;i++)
    scanf(
    "%I64d",&num[i]);
    CreateTree(
    1,1,n);

    while(m--)
    {
    scanf(
    "%*c%c",&c);
    if(c == 'Q')
    {
    sum
    = 0;
    scanf(
    "%d%d",&x1,&x2);
    find(
    1,x1,x2);
    printf(
    "%I64d\n",sum);
    }
    else
    {
    scanf(
    "%d%d%d",&x1,&x2,&x3);
    insert(
    1,x1,x2,x3);
    }
    }
    }
    }

    int main()
    {
    Init();
    return 0;
    }

    8.pku2528 Mayor’s posters
    成段更新,区间统计(离散化)

    一个很恶心的题目,昨天晚上看了题意,上网了解了一下离散化。离散化就是为了缩 短线段的范围,如两个线段(1,6)和(4,9),离散化一下就是1->1,6->3,4->2,9->4,那么离散后的线段就 是(1,3)和(2,4),把线段长度从(1,9)缩短到了(1,4),这种离散化是很实用的。离散的过程就是先把线段的坐标保存下来 (1,6,4,9),再排序(1,4,6,9),之后对应(1->1,4->2,6->3,9->4),再根据这个对应修改原先 的线段就好了。

    写的时候很恶心,一直re,很久以后试试看的态度改了MAX_N,从10005改成30005就行了。应该是用来排序的那个数组开小了

    View Code
    #include <iostream>
    #include
    <algorithm>
    using namespace std;
    #define MAX_N 30005 //一开始开10005 就RE了

    int n; //线段个数
    int num[10005];
    int pos[10005][2];
    bool vis[10000005];
    int hash[10000005];
    int set[8*MAX_N];

    struct node
    {
    int left;
    int right;
    int data;
    };
    node T[
    8*MAX_N];

    void CreateTree(int ini,int a, int b)
    {
    T[ini].left
    = a;
    T[ini].right
    = b;
    T[ini].data
    = -1;
    if(a >= b)
    return;
    int mid = (a+b)>>1;
    CreateTree(ini
    *2,a,mid);
    CreateTree(ini
    *2+1,mid+1,b);
    }

    void insert(int ini,int a,int b,int color)
    {
    if(T[ini].left == a && T[ini].right == b)
    {
    T[ini].data
    = color;
    //return;
    }
    else
    {
    if(T[ini].data > 0 && T[ini].data != color)
    {
    T[ini
    *2].data = T[ini].data;
    T[ini
    *2+1].data = T[ini].data;
    T[ini].data
    = 0;
    }
    else if(T[ini].data == -1)
    {
    T[ini].data
    = 0;
    }
    int mid = (T[ini].left+T[ini].right)>>1;
    if(b <= mid)
    insert(ini
    *2,a,b,color);
    else if(a > mid)
    insert(ini
    *2+1,a,b,color);
    else
    {
    insert(ini
    *2,a,mid,color);
    insert(ini
    *2+1,mid+1,b,color);
    }
    }
    }

    void find(int ini)
    {
    if(T[ini].left == T[ini].right)
    {
    if(T[ini].data > 0)
    num[T[ini].data]
    ++;

    return;
    }

    if(T[ini].data == -1)
    return;
    else if(T[ini].data > 0)
    {
    num[T[ini].data]
    ++;
    return;
    }
    else if(T[ini].data == 0)
    {
    find(ini
    *2);
    find(ini
    *2+1);
    }
    }

    int cmp(int a,int b)
    {
    return a<b;
    }
    void Init()
    {
    int i;
    memset(vis,
    0,sizeof(vis));

    int j = 0;
    scanf(
    "%d",&n);
    CreateTree(
    1,1,8*n);
    for(i=0;i<n;i++) //离散化
    {
    scanf(
    "%d%d",&pos[i][0],&pos[i][1]);
    if(vis[pos[i][0]] == 0)
    {
    set[j++] = pos[i][0];
    vis[pos[i][
    0]] = 1;
    }
    if(vis[pos[i][1]] == 0)
    {
    set[j++] = pos[i][1];
    vis[pos[i][
    1]] = 1;
    }
    }
    sort(
    set,set+j,cmp);
    for(i=0;i<=j;i++)
    {
    hash[
    set[i]] = i+1;
    }

    for(i=0;i<n;i++)
    {
    pos[i][
    0] = hash[pos[i][0]];
    pos[i][
    1] = hash[pos[i][1]];
    insert(
    1,pos[i][0],pos[i][1],i+1);
    }
    }

    int main()
    {
    int i,t;
    scanf(
    "%d",&t);
    while(t--)
    {
    memset(num,
    0,sizeof(num));
    int sum = 0;
    Init();
    find(
    1);
    for(i=1;i<=n;i++)
    {
    if(num[i] > 0)
    sum
    ++;
    }
    printf(
    "%d\n",sum);
    }
    return 0;
    }

    9.hdu2795 Billboard
    更新节点,询问特殊(暑假的时候不会线段树被这水题狂虐)

    一开始不能理解,不会建树,一直以为是用10^9,实际上只要20000*4就行了。而data表示最大值。想通这个就好过了。

    View Code
    #include <iostream>
    using namespace std;
    #define MAX_N 200000

    int h,w,n;
    struct node
    {
    int left;
    int right;
    int data; //表示这一段中最大的数
    };
    node T[
    4*MAX_N];

    int Max(int a,int b)
    {
    return a>b?a:b;
    }

    void CreateTree(int ini,int a,int b)
    {
    T[ini].left
    = a;
    T[ini].right
    = b;
    T[ini].data
    = w; //一开始最大都是宽度
    if(a == b)
    {
    return;
    }
    else
    {
    int mid = (a + b) >> 1;
    CreateTree(ini
    *2,a,mid);
    CreateTree(ini
    *2+1,mid+1,b);
    }
    }

    void insert(int ini,int a)
    {
    if(T[ini].left == T[ini].right)
    {
    printf(
    "%d\n",T[ini].left);
    T[ini].data
    -= a;
    }
    else
    {
    if(T[ini*2].data >= a)
    {
    insert(ini
    *2,a);
    }
    else
    {
    insert(ini
    *2+1,a);
    }
    T[ini].data
    = Max(T[ini*2].data,T[ini*2+1].data);
    }


    }

    int main()
    {
    int i,num;
    while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    {
    if(h < n)
    CreateTree(
    1,1,h);
    else
    CreateTree(
    1,1,n);
    //建树按照min(h,n)来建,这样就保证最大时n。
    for(i=0;i<n;i++)
    {
    scanf(
    "%d",&num);
    if(num > T[1].data)
    {
    printf(
    "-1\n");
    }
    else
    insert(
    1,num);
    }
    }
    return 0;
    }

    10.pku3667 Hotel
    成段更新,寻找空间(经典类型,求一块满足条件的最左边的空间)

    .
    11.hdu1540 Tunnel Warfare
    更新节点,询问节点所在区间(同上一道Hotel一样类型的题目)

    .
    12.hdu2871 Memory Control
    hotel变形题目,三个都函数一样(vector忘记清空检查了好久)

    .
    13.hdu3016 Man Down
    成段更新,单点查询(简单线段树+简单DP)

    .
    14.hdu1542 Atlantis
    矩形面积并,扫描线法(发现我们HDU的队员的矩形面积交模板基本都是在最坏情况下更新到底,宁波惨痛的教训啊..)

    .
    15.hdu1255 覆盖的面积
    同上,扫描线法,我多加了一个系数csum,来统计覆盖两次的长度(156MS,第一次做线段树排到第一,纪念下)

    .
    16.hdu1828 Picture
    扫描线,同面积统计,加了一个num_Seg统计一个扫描区域里的边

    .
    17.pku1436 Horizontally Visible Segments
    成段更新,成段询问(染色问题,坐标*2后很简单,最后统计用暴力- -)

    .
    18.pku3225 Help with Intervals
    成段更新,总询问区间(有个异或操作比较新颖)

    .
    19.pku2482 Stars in Your Window
    成段更新,区间最值 + 扫描线(转化成区间最值有点巧妙,数据太TMD的恶心了,中间二分的地方会int溢出,检查了半个小时)

    .
    20.pku2828 Buy Tickets
    思维很巧妙,倒过来做的话就能确定此人所在的位置

    .
    21.pku2464 Brownie Points II
    更新节点,区间求和 + 扫描线(很好玩的一道题目,用两个线段树沿着扫描线更新,然后按”自己最多,对方最少”的方案一路统计)
    (因为两棵树,我就直接写成类了)

    .
    22.pku3145 Harmony Forever
    查找一个区间内最左边的数,询问的val大的话用线段树,小的话线性扫描,很囧的题目

    .
    23.pku2886 Who Gets the Most Candies?
    寻找区间中的左数第N个数,约瑟夫环(学到了反素数表,可以不用把所有数字预处理出来了)

    .
    24.pku2991 Crane
    记录了线段的两端点以及转过的角度,成段的转,超有意思的题目,做了之后会对线段树理解更深刻
    (wy教主推荐的,不过我的代码写的太搓了..没啥学习的价值)

    .
    25.hdu1823 Luck and Love
    二维线段树,没啥意思,代码量大了一倍而已,题目和运用范围都没一维的广,随便找了道题目练习下就好

  • 相关阅读:
    借壳上市[来自百度]
    DIY协同办公平台(C/S)系列3之内部邮箱篇
    测试用例设计场景法
    客户关系管理系统提高企业对客户的响应速度
    CRM--销售管理的灵药
    CRM的两个问题
    需求分析是CRM系统实施的关键
    如何实施CRM客户关系管理系统
    CRM的三重境界
    企业需要更好的认识客户关系管理系统
  • 原文地址:https://www.cnblogs.com/silencExplode/p/1968524.html
Copyright © 2020-2023  润新知