• CDQ分治与整体二分总结


         Cdq分治和整体二分是两个很奇妙的东西。他们都是通过离线的思想来进行优化,从而更快的求出解。

      整体二分通俗的讲就是二分答案,但是它了不起的地方是一下子把所有的答案都二分出来了,从而可以一下子得出所有查询。

      CDQ分治通俗的讲就是二分查询。通常的做法是把所有的查询分成两半,然后通过递归先计算出左边一半的所有的查询,然后通过这些已知的左半边的值来更新右半边的值。这里,最最重要的思想是通过左半边来更新右半边。更具体一点,就是用左半边的修改来更新右半边的查询。

    重要的事情说话三遍:

      CDQ分治就是通过左半边的修改来更新右半边的查询

      CDQ分治就是通过左半边的修改来更新右半边的查询!

      CDQ分治就是通过左半边的修改来更新右半边的查询

          CDQ的主要作用就是降维。因为当你二分查询的时候,你可以保证左半边的查询都满足你二分前的顺序。

     

    一、整体二分

    1. 最经典的题目:带修改的区间第k小数(hdu5412

    因为相同的题目太多了,挑了一道比较新的题。其实就是题面不一样。

             题目意思:

             给你N个数,有两种询问。一个是修改第K个数的值,二是询问一个区间内的第k小的数,输出这个数。

             所以,具体的做法就是二分答案。如果比猜测的数字小的个数比较多,那么答案一定在左边的区间内,反之就在右边的区间内。然后递归来继续这个操作。

       这是写的第一道整体二分,不要问我为什么和网上的代码几乎一模一样。我只是因为看了很久才看懂,所以几乎就背出来了……

    代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <cctype>
    #define INF 0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 323400
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    
    
    int dat[maxn];
    void add(int k,int val){
        while(k<maxn){
            dat[k]+=val;
            k+=lowbit(k);
        }
    }
    int query(int k){
        int sum=0;
        while(k>0){
            sum+=dat[k];
            k-=lowbit(k);
        }
        return sum;
    }
    
    struct {
        //sign x query val k
        int s,x,val,q,k,l,r,cur;
    }q[maxn],q1[maxn],q2[maxn];
    int A[maxn];
    int temp[maxn];
    int ans[maxn];
    //×ó±ÕÓÒ±Õ 
    void div_solve(int head,int tail,int l,int r){
        //cout<<head<<' '<<tail<<' '<<l<<' '<<r<<endl;
        if(head>tail)return ;
        if(l==r){
            for(int i=head;i<=tail;++i){
                if(q[i].s==3)
                    ans[q[i].q]=l;
            }
            return ;
        }
        int mid=l+r>>1;
        for(int i=head;i<=tail;++i){
            if(q[i].s==1 && q[i].val<=mid) add(q[i].x,1); 
            else if(q[i].s==2 && q[i].val<=mid) add(q[i].x,-1);
            else if(q[i].s==3) temp[i]=query(q[i].r)-query(q[i].l-1);     
        }
        for(int i=head;i<=tail;++i){
            if(q[i].s==1 && q[i].val<=mid) add(q[i].x,-1); 
            else if(q[i].s==2 && q[i].val<=mid) add(q[i].x,1);
        }
        int l1=0,l2=0;
        for(int i=head;i<=tail;++i){
            if(q[i].s==3){
                if(q[i].cur+temp[i]>=q[i].k){
                    q1[l1++]=q[i];    
                }
                else{
                    q[i].cur+=temp[i];
                    q2[l2++]=q[i];
                }
            }
            else
            {
                if(q[i].val<=mid){
                    q1[l1++]=q[i];
                }
                else{
                    q2[l2++]=q[i];
                }
            }
        }
        for(int i=0;i<l1;++i){
            q[i+head]=q1[i];    
        }
        for(int i=0;i<l2;++i){
            q[i+head+l1]=q2[i];
        }
        div_solve(head,head+l1-1,l,mid);
        div_solve(head+l1,tail,mid+1,r);
    }
    
    int main()
    {
        int n;
        while(~scanf("%d",&n)){
            int a,b,c,d;
            int cnt=0;
            for(int i=1;i<=n;++i){
                scanf("%d",&a);
                A[i]=a;
                q[cnt].s=1;q[cnt].x=i;
                q[cnt].cur=0;
                q[cnt++].val=a;
            }
            int t,tt=0;
            scanf("%d",&t);
            for(int i=1;i<=t;++i){
                scanf("%d",&a);
                if(a==1){
                    scanf("%d%d",&b,&c);
                    q[cnt].s=2;q[cnt].x=b;q[cnt].cur=0;
                    q[cnt++].val=A[b];
                    q[cnt].s=1;q[cnt].x=b;q[cnt].cur=0;
                    q[cnt++].val=c;
                    A[b]=c;
                }
                else{
                    scanf("%d%d%d",&a,&b,&c);
                    q[cnt].s=3;q[cnt].l=a;q[cnt].q=++tt;
                    q[cnt].cur=0;
                    q[cnt].r=b;q[cnt++].k=c;
                }
            }
            div_solve(0,cnt-1,0,INF);
            for(int i=1;i<=tt;++i)
                printf("%d
    ",ans[i]);                
        }
        return 0;
    }
    View Code

    2.POI 2011 Meteors

    //因为bzoj现在都要收费了,找了半天终于找到免费的。

    http://main.edu.pl/en/archive/oi/18/met

    题目意思:

    一个行星有一条圆形的轨道。这条轨道被分成了m份,这些轨道分别属于n个国家。一个国家可以拥有多个轨道。在轨道周围会有流星雨落下,现在各个国家需要收集一些流星雨。问你需要经过多少时间,各个国家才能完成他们的收集任务。

    因为问的是时间,所以第一个想到是二分时间。接下来在维护一个线段树,用来区间修改。然后再根据二分时间,检查是否满足要求。继续二分,直到找到解。其中的一个处理是在t+1的时间再加一个无限大的流星,用来确定是不是能够成功收集。

    代码:

     

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define INF 0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 301234
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    const ll INF2=(0x3f3f3f3f)*100ll;
    
    //bit Çø¼äÐÞ¸Ä µ¥µã²éѯ 
    ll dat[maxn];
    //×ó±ÕÓÒ¿ª
    
    void init(){
        memset(dat,0,sizeof(dat));
    }
    void add(int l,int r,int val){
        while(l<maxn){
            dat[l]+=val;
            l+=lowbit(l);
        }
        while(r<maxn){
            dat[r]-=val;
            r+=lowbit(r);
        }
    }
    ll query(int k){
        ll sum=0;
        while(k>0){
            sum+=dat[k];
            k-=lowbit(k);
        }
        return sum;
    }
    
    struct edge{
        int to,next;
    }G[maxn];
    int head[maxn];
    void add_edge(int from,int to,int &cnt){
        edge e;
        e.to=to;e.next=head[from];
        G[++cnt]=e;
        head[from]=cnt;
    }
    
    struct node{
        int l,r,num;
    }Q[maxn];
    ll cur[maxn];
    int A[maxn],ID[maxn],T[maxn],Ans[maxn];
    int n,m,t;
    int temp[maxn],temp2[maxn];
    
    void solve(int start,int tail,int l,int r){
        if(start>tail) return ;
        if(l==r){
            for(int i=start;i<=tail;++i){
                int d=ID[i];
                Ans[d]=l;
            }
            return ;
        }
        //init();
        int mid=(l*1ll+r)>>1;
        for(int i=l;i<=mid;++i){
            int l=Q[i].l,r=Q[i].r,num=Q[i].num;
            if(l>r){
                add(l,m+1,num);
                add(1,r+1,num);
            }
            else
                add(l,r+1,num);
        }
        int l1=0,l2=0;
        for(int i=start;i<=tail;++i){
            int d=ID[i];
            ll cnt=0;
            for(int j=head[d];j;j=G[j].next){
                int to=G[j].to;
                cnt+=query(to);
                if(cnt>INF)break;
            }
            if(cnt+cur[d]>=T[d]){
                temp[l1++]=d;
            }
            else{
                temp2[l2++]=d;
                cur[d]+=cnt;
            }
        }
        for(int i=0;i<l1;++i){
            ID[start+i]=temp[i];
        }
        for(int i=0;i<l2;++i){
            ID[start+l1+i]=temp2[i];
        }
        for(int i=l;i<=mid;++i){
            int l=Q[i].l,r=Q[i].r,num=Q[i].num;
            if(l>r){
                add(l,m+1,-num);
                add(1,r+1,-num);
            }
            else
                add(l,r+1,-num);
        }
        //cout<<l<<" "<<r<<endl;
        solve(start,start+l1-1,l,mid);
        solve(start+l1,tail,mid+1,r);
    }
    
    int Scan(){
        int res=0, ch;
        ch=getchar();
        //windows»Ø³µ
      linux»Ø³µ
      ·ÀÖ¹Êý¾ÝÖÐûÓÐÈ¥³ý
    
        if(ch==10) ch=getchar();
        if(ch>='0'&&ch<='9')
            res=ch-'0';
        else return -1;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+ch-'0';
        return res;
    }
    void Out(ll a){
        if(a>9)
            Out(a/10);
        putchar(a%10+'0');
    }
    int main()
    {
        //scanf("%d%d",&n,&m);
        n=Scan();m=Scan();
        memset(head,0,sizeof(head));
        int tot=0;
        for(int i=1;i<=m;++i){
            //scanf("%d",&A[i]);
            A[i]=Scan();
            add_edge(A[i],i,tot);
        }
        for(int i=1;i<=n;++i){
            //scanf("%d",&T[i]);
            T[i]=Scan();
            ID[i]=i;
        }
        //scanf("%d",&t);
        t=Scan();
        int l,r,num;
        for(int i=1;i<=t;++i){
            //scanf("%d%d%d",&l,&r,&num);
            l=Scan();r=Scan();num=Scan();
            Q[i].l=l;Q[i].r=r;
            Q[i].num=num;
        }
        t+=1;
        Q[t].num=INF;Q[t].l=1;Q[t].r=m;
        //memset(cur,0,sizeof(cur));
        solve(1,n,1,t);
        for(int i=1;i<=n;++i){
            if(Ans[i]==t){
                puts("NIE");
            }
            else{
                //printf("%d
    ",Ans[i]);
                Out(Ans[i]);
                putchar('
    ');
            }
        }
        
        return 0;
    }
    View Code

    其他学习资料:http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html

    二、CDQ分治

    1.Boring Class(hdu5324)

             题目意思:给你两个序列,分别为L序列和R序列。求一个最长的序列,满足对于每个Vi,Vj,L[Vi]>=L[Vj] 并且R[Vi]<=R[Vj],同时还要的是字典序最小这个条件。

             这题是典型的CDQ分治的题目。因为有三维,顺序维、L维和R维,我们不好处理。所以这个时候就可以通过CDQ分治来二分它的顺序。这样就可以保证在CDQ的过程中,时间顺序一定是满足的。接下来在CDQ中,我们不妨按照R来排序,这样可以确定R也满足顺序,然后再进行DP就可以得出结果了。其中要注意的是从右往左DP,这样可以求出字典序的最小。

             代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include<cassert>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 50099
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    
    
    int tot;
    int L[maxn],R[maxn];
    int Num[maxn*2],D[maxn];
    struct node{
        int l,r,id;
        bool operator<(const node &B)const{
            if(r!=B.r)return r<B.r;
            if(l!=B.l)return l>B.l;
            return id<B.id;
        }
    }q1[maxn],q2[maxn];
    int dat[maxn*2];
    void update(int k,int val){
        while(k<tot+10){
            dat[k]=max(dat[k],val);
            k+=lowbit(k);
        }
    }
    void clear(int k){
        while(k<tot+10){
            dat[k]=0;
            k+=lowbit(k);
        }
    }
    int query(int k){
        int Max=0;
        while(k>0){
            Max=max(Max,dat[k]);
            k-=lowbit(k);
        }
        return Max;
    }
    
    
    void cdq(int l,int r){
        if(l==r)return;
        int mid=(l+r)/2;
        cdq(mid+1,r);
        for(int i=l;i<=mid;++i){
            q1[i].l=L[i];q1[i].r=R[i];q1[i].id=i;    
        }
        for(int i=mid+1;i<=r;++i){
            q2[i].l=L[i];q2[i].r=R[i];q2[i].id=i;    
        }
        sort(q1+l,q1+mid+1);
        sort(q2+mid+1,q2+r+1);
        for(int i=mid,j=r;i>=l;--i){
            while(j>mid && q2[j].r>=q1[i].r){
                update(q2[j].l,D[q2[j].id]);
                j--;
            }
            D[q1[i].id]=max(D[q1[i].id],query(q1[i].l)+1);
        }
        for(int i=mid+1;i<=r;++i){
            clear(q2[i].l);
        }
        cdq(l,mid);    
    }
    
    int Scan(){
        int res=0, ch;
        ch=getchar();
        //windows»Ø³µ
      linux»Ø³µ
      ·ÀÖ¹Êý¾ÝÖÐûÓÐÈ¥³ý
    
        if(ch==10) ch=getchar();
        if(ch>='0'&&ch<='9')
            res=ch-'0';
        else return -1;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+ch-'0';
        return res;
    }
    void Out(ll a){
        if(a>9)
            Out(a/10);
        putchar(a%10+'0');
    }
    
    
    int main()
    {
        int n;
        //~(n=Scan())
        //freopen("data.in","r",stdin);
        while(~scanf("%d",&n)){
            tot=0;
            for(int i=1;i<=n;++i){
                scanf("%d",&L[i]);
                //L[i]=Scan();
                Num[tot++]=L[i];
            }
            for(int i=1;i<=n;++i){
                scanf("%d",&R[i]);
                //R[i]=Scan();
                Num[tot++]=R[i];
            }
            sort(Num,Num+tot);
            tot=unique(Num,Num+tot)-Num;
            for(int i=1;i<=n;++i){
                L[i]=(lower_bound(Num,Num+tot,L[i])-Num)+1;
                R[i]=(lower_bound(Num,Num+tot,R[i])-Num)+1;    
            }
        //    cout<<"ok"<<endl;
            for(int i=1;i<maxn;++i)
                D[i]=1;
            cdq(1,n);
            int ans=0;
            for(int i=1;i<=n;++i){
                ans=max(D[i],ans);
            }
            printf("%d
    ",ans);
            //Out(ans);putchar('
    ');
            int pre=0;
            for(int i=1;i<=n;++i){
                if(D[i]==ans && (pre==0 || ( L[pre]>=L[i] && R[pre]<=R[i]))){
                    ans--;
                    if(pre)putchar(' ');
                    printf("%d",i);    
                    //Out(i);
                    pre=i;
                }
            }
            putchar('
    ');
        }
        return 0;
    }
    View Code

    2. Pinball Game 3Dhdu4742

             题目意思:给你三个序列X,Y,Z求最长上升序列的长度。同时输出可以构成最长上升序列的方法数。

             和之前的一题几乎一样,多了一个维护方法数。所以树状数组不仅要维护一个Dp的值,同时还要维护一个方法数。如果Dp更新了,方法数就是更新它的值,反之,在原来的基础上要加上那种方法的个数。

             代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 100009
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,ll>PII;
    typedef pair<PII,int>PPI;
    
    int Fu[maxn*3];
    ll Num[maxn];
    int D[maxn];
    const ll MOD=(1<<30);
    struct node{
        int x,y,z;
        bool operator <(const node&B) const{
            if(x!=B.x) return x<B.x;
            if(y!=B.y) return y<B.y;
            return z<B.z;
        }
    }A[maxn];
    struct node2{
        int x,y,z,id;
        bool operator<(const node2&B)const{
            if(y!=B.y) return y<B.y;
            if(z!=B.z) return z<B.z;
            return id<B.id;
        }
    }q1[maxn],q2[maxn];
    PII dat[maxn*3];
    void update(int k,int val,ll num){
        while(k<maxn*3){
            if(val>dat[k].X){
                dat[k].X=val;
                dat[k].Y=num;
            }
            else if(val==dat[k].X){
                dat[k].Y+=num;
                dat[k].Y%=MOD;
            }
            k+=lowbit(k);
        }
    }
    PII  query(int k){
        PII Max=MP(0,0);
        while(k>0){
            if(dat[k].X>Max.X){
                Max=dat[k];
            }
            else if(dat[k].X==Max.X){
                Max.Y+=dat[k].Y;
                Max.Y%=MOD;
            }
            k-=lowbit(k);
        }
        return Max;
    }
    void clear(int k){
        while(k<maxn*3){
            dat[k]=MP(0,0);
            k+=lowbit(k);
        }
    }
    void cdq(int l,int r){
        if(l==r)return ;
        int mid=l+r>>1;
        cdq(l,mid);
        for(int i=l;i<=mid;++i){
            q1[i].x=A[i].x;q1[i].y=A[i].y;
            q1[i].z=A[i].z;q1[i].id=i;
        }
        for(int i=mid+1;i<=r;++i){
            q2[i].x=A[i].x;q2[i].y=A[i].y;
            q2[i].z=A[i].z;q2[i].id=i;
        }
        sort(q1+l,q1+mid+1);
        sort(q2+mid+1,q2+r+1);
        for(int i=mid+1,j=l;i<=r;++i){
            while(j<=mid && q1[j].y<=q2[i].y){
                update(q1[j].z,D[q1[j].id],Num[q1[j].id]);
                j++;
            }
            PII temp=query(q2[i].z);
            if(D[q2[i].id]<temp.X+1){
                D[q2[i].id]=temp.X+1;
                Num[q2[i].id]=temp.Y;
            }
            else if(D[q2[i].id]==temp.X+1){
                Num[q2[i].id]+=temp.Y;
                Num[q2[i].id]%=MOD;
            }
        }
        for(int i=l;i<=mid;++i){
            clear(q1[i].z);
        }
        cdq(mid+1,r);
    }
    
    int Scan(){
        int res=0, ch;
        ch=getchar();
        //windows»Ø³µ
      linux»Ø³µ
      ·ÀÖ¹Êý¾ÝÖÐûÓÐÈ¥³ý
    
        if(ch==10) ch=getchar();
        if(ch>='0'&&ch<='9')
            res=ch-'0';
        else return -1;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+ch-'0';
        return res;
    }
    void Out(ll a){
        if(a>9)
            Out(a/10);
        putchar(a%10+'0');
    }
    int main()
    {
        int T;
        //scanf("%d",&T);
        T=Scan();
        while(T--){
            int n;
            //scanf("%d",&n);
            n=Scan();
            int tot=0;
            for(int i=1;i<=n;++i){
                //scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].z);
                A[i].x=Scan();A[i].y=Scan();A[i].z=Scan();
                Fu[tot++]=A[i].x;
                Fu[tot++]=A[i].y;
                Fu[tot++]=A[i].z;
            }
            sort(Fu,Fu+tot);
            for(int i=1;i<=n;++i){
                D[i]=Num[i]=1;
                A[i].x=lower_bound(Fu,Fu+tot,A[i].x)-Fu+1;
                A[i].y=lower_bound(Fu,Fu+tot,A[i].y)-Fu+1;
                A[i].z=lower_bound(Fu,Fu+tot,A[i].z)-Fu+1;
            }
            sort(A+1,A+n+1);
            cdq(1,n);
            int Max=0;
            for(int i=1;i<=n;++i){
                Max=max(Max,D[i]);            
            }
            ll sum=0;
            for(int i=1;i<=n;++i){
                if(D[i]==Max){
                    sum=sum+Num[i];
                    sum%=MOD;
                }
            }
            printf("%d %I64d
    ",Max,sum);
        }
        return 0;
    }
    View Code

    3. Machine Works(hdu3842)

             这是2011WorldFinal的一道题目,所以做的人不多。要是我当时看到是WorldFinal的题,肯定吓得直接跳过了。但是事实上难度还可以。

             题目意思:

             初始时,给你一笔资金C元,以及一段时间D天。在其中的某天会提供给你购买机器的机会,你可以选择购买或者不购买。买机器需要花费P元,卖出可以获得R元,从够买机器的第二天起,到卖出机器的前一天,你可以每天获得G元。最后一天将卖出所有机器。同时,由于场地限制,最多只能同时拥有一台机器。

             首先我们可以用D[i]来维护前一个状态结束,刚刚到达i这个机器时,所能拥有的最大值。

                D[i]=max{D[j]-P[j]+R[j]+G[j]*(day[i]-day[j]-1)}

             因为j的信息都是已知的,所以可以化解为

                D[i]=C+k*day[i];

             所以也就化解为斜率优化DP的问题了。

             所以我们接下来按照斜率从小到大来排序,用一个队列来维护。队列中的元素满足k是递增的。所以队尾的元素一定在某些x时候会比队尾的前一个元素大。现在当你要新加入一个元素到末尾的时候,新加入的元素可能无论在什么时候都比原先在队尾的元素大,这样就删掉那个元素。

             同时对于队首的维护,当目前的x不是最大时,删除这个队首的值。DP一下就可以了。

             代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 123456
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    //19:52
    
    
    ll D[maxn];
    struct node{
        int day,pri,ret,val,id;
        bool operator <(const node &B)const {
            return day<B.day;
        }
    }A[maxn];
    struct node2{
        int day,pri,ret,val,id;
        bool operator <(const node2 &B)const {
            if(val==B.val){
                ll t1=D[id]+ret-pri-1ll*(day+1)*val;
                ll t2=D[B.id]+B.ret-B.pri-1ll*(B.day+1)*B.val;
                return t1<t2;
            }
            return val<B.val;
        }
    }q1[maxn],q2[maxn];
    ll K[maxn],B[maxn];
    ll f(int i,int x){
        ll ans=K[i]*x+B[i];
        return ans;
    }
    bool check(int i1,int i2,ll k3,ll b3){
        ll k1=K[i1],b1=B[i1],k2=K[i2],b2=B[i2];
        return 1.0*(k3-k2)*(b1-b3)-1.0*(b2-b3)*(k3-k1)<0;    
        //return (double)(k2-k1)*(b3-b1)-(double)(k3-k1)*(b2-b1)<0;            
    }
    void cdq(int l,int r){
        if(l==r)return ;
        int mid=l+r>>1;
        cdq(l,mid);
        for(int i=l;i<=mid;++i){
            q1[i].day=A[i].day;q1[i].pri=A[i].pri;
            q1[i].ret=A[i].ret;q1[i].val=A[i].val;
            q1[i].id=A[i].id;
        }
        for(int i=mid+1;i<=r;++i){
            q2[i].day=A[i].day;q2[i].pri=A[i].pri;
            q2[i].ret=A[i].ret;q2[i].val=A[i].val;
            q2[i].id=A[i].id;
        }
        sort(q1+l,q1+mid+1);
        int head=0,tail=-1;
        for(int i=l;i<=mid;++i){
            if(D[q1[i].id]<q1[i].pri)continue;
            ll t1=q1[i].val;
            ll t2=D[q1[i].id]+q1[i].ret-q1[i].pri-1ll*(q1[i].day+1)*q1[i].val;
            
    //        if(tail-head+1<2){
    //            K[++tail]=t1;
    //            B[tail]=t2;
    //            //if(head-tail==1 && K[head]==K[tail] && B[head]<=B[tail])head++;
    //        }
    //        else{
            
                while(tail>head && !check(tail-1,tail,t1,t2))tail--;
                K[++tail]=t1;
                B[tail]=t2;
            //}
        }
        for(int i=mid+1;i<=r;++i){
            int d=q2[i].day;
            while(head<tail && f(head,d)<=f(head+1,d))head++;    
            ll temp=f(head,d);
            if(temp<0)continue;
            D[q2[i].id]=max(temp,D[q2[i].id]);
        }
        cdq(mid+1,r);
    }
    
    int main()
    {
        int n,c,d;
        int tt=0;
        while(~scanf("%d%d%d",&n,&c,&d)){
            if(n==0 && c==0 && d==0)break;
            D[0]=c;
            A[0].id=0;A[0].day=0;A[0].val=0;A[0].pri=0;A[0].ret=0;
            for(int i=1;i<=n;++i){
                scanf("%d%d%d%d",&A[i].day,&A[i].pri,&A[i].ret,&A[i].val);
                A[i].id=i;
                D[i]=c;
            }
            A[n+1].day=d+1;A[n+1].id=n+1;
            A[n+1].pri=A[n+1].val=A[n+1].ret=0;
            D[n+1]=c;
            sort(A+1,A+n+1);
            cdq(0,n+1);
            printf("Case %d: %I64d
    ",++tt,D[n+1]);
        }
        return 0;
    }
    View Code

    4. 动态逆序对(BZOJ3295)

             题目意思:给你一个序列求每次删除一个元素之前的逆序对的个数。

             假设你要删除一个元素,那么减少的逆序对的个数不仅和他前面位置的有关,还和他后面位置的数有关。所以假设已经知道在最初状态时在他前面和后面分别的逆序对数。在删除的时候,更新这两个值,问题就解决了。

             至于逆序对的个数,预处理一下就可以了。

       代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 123456
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    
    ll dat[maxn];
    void update(int k,int val){
        while(k<maxn){
            dat[k]+=val;
            k+=lowbit(k);
        }
    }
    ll query(int k){
        ll sum=0;
        while(k>0){
            sum+=dat[k];
            k-=lowbit(k);    
        }
        return sum;
    }
    int A[maxn];
    int Pos[maxn];
    ll L[maxn],R[maxn];
    struct node{
        int val,id;
        bool operator <(const node &B)const {
            return Pos[val]<Pos[B.val];
        }
    }Q[maxn],q1[maxn],q2[maxn];
    ll Ans[maxn];
    int n,m;
    void solve(int l,int r){
        if(l==r){
        //    cout<<Pos[Q[l].val]<<" "<<L[Pos[Q[l].val]]<<" "<<R[Pos[Q[l].val]]<<endl;
            Ans[l]=L[Pos[Q[l].val]]+R[Pos[Q[l].val]];
            return ;
        }
        int mid=l+r>>1;
        solve(l,mid);
        int l1=0,l2=0;
        for(int i=l;i<=mid;++i){
            q1[l1++]=Q[i];
        }
        for(int i=mid+1;i<=r;++i){
            q2[l2++]=Q[i];
        }
        sort(q1,q1+l1);
        sort(q2,q2+l2);
        int j=0;
        for(int i=0;i<l2;++i){
            while(j<l1 && Pos[q1[j].val]<Pos[q2[i].val]){
                update(q1[j].val,1);
                //cout<<" "<<Pos[q1[j].val]<<" "<<n<<" "<<query(n)<<endl;
                j++;
            }
            int ps=Pos[q2[i].val];
            L[ps]-=query(n)-query(q2[i].val);
        }
        for(int i=0;i<j;++i){
            update(q1[i].val,-1);
        }
        //----
        j=l1-1;
        for(int i=l2-1;i>=0;--i){
            while(j>=0 && Pos[q1[j].val]>Pos[q2[i].val]){
                update(q1[j].val,1);
                j--;
            }
            int ps=Pos[q2[i].val];
            R[ps]-=query(q2[i].val);
        }
        for(int i=l1-1;i>j;--i){
            update(q1[i].val,-1);
        }
        solve(mid+1,r);
    }
    
    
    
    int main()
    {
        while(~scanf("%d%d",&n,&m)){
            memset(dat,0,sizeof(dat));
            ll sum=0;
            for(int i=1;i<=n;++i){
                scanf("%d",&A[i]);
                L[i]=query(n)-query(A[i]);
                sum+=L[i];
                update(A[i],1);
                Pos[A[i]]=i;
            }
            memset(dat,0,sizeof(dat));
            for(int i=n;i>=1;--i){
                R[i]=query(A[i]);
                update(A[i],1);
            }    
            int a;
            for(int i=1;i<=m;++i){
                scanf("%d",&a);
                Q[i].val=a;
                Q[i].id=i;
            }
            memset(dat,0,sizeof(dat));
            solve(1,m);
            for(int i=1;i<=m;++i){
                printf("%lld
    ",sum);
                sum-=Ans[i];
            }
        }
        return 0;
    }
    View Code

    5. Crowd(hdu4456)

             题目意思:给你一张图,有两种查询,1.是给某个点的值增加Z  2.是查询曼哈顿距离小于某个点的值的和。

             首先,需要的是坐标轴旋转。然后就可以用CDQ分治,或者是二维树状数组来搞了。

             这篇讲的很好,我就不废话了。

         http://www.aiuxian.com/article/p-2286542.html

    代码:树状数组

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 1
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    
    void change(int &x,int &y,int n){
        int t=x-y+n;
        y=x+y-1;
        x=t;
    }
    const int MOD=3001003;
    int dat[MOD];
    int num[MOD];
    int Hash(int x){
        int t=x%MOD;
        while(1){
            if(num[t]==x || num[t]==-1){
                num[t]=x;
                return t;
            }
            t++;
            if(t==MOD)t=0;
        }
        return -1;
    }
    int gethash(int x){
        int t=x%MOD;
        while(1){
            if(num[t]==-1 || num[t]==x)return t;
            t++;
            if(t==MOD)t=0;
        }
        return -1;
    }
    int Bound;
    void add(int x,int y,int add){
        for(int i=x;i<Bound;i+=lowbit(i)){
            for(int j=y;j<Bound;j+=lowbit(j)){
                dat[Hash(i*Bound+j)]+=add;
            }
        }
    }
    int getsum(int x,int y){
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i)){
            for(int j=y;j>0;j-=lowbit(j)){
                ans+=dat[gethash(i*Bound+j)];
            }
        }
        return ans;
    }
    int query(int a,int b,int c,int d){
        int ans=0;
        a=max(a,1);b=max(b,1);
        c=min(Bound-1,c);
        d=min(Bound-1,d);
        ans=getsum(c,d)+getsum(a-1,b-1)
            -getsum(a-1,d)-getsum(c,b-1);
        return ans;
    }
    int main()
    {
        int n,m;
        while(1){
            scanf("%d",&n);
            if(n==0)break;
            scanf("%d",&m);
            Bound=n*2+1;
            memset(dat,0,sizeof(dat));
            memset(num,-1,sizeof(num));
            int a,x,y,z;
            for(int i=0;i<m;++i){
                scanf("%d%d%d%d",&a,&x,&y,&z);
                change(x,y,n);
                if(a==1){
                    add(x,y,z);
                }
                else{
                    printf("%d
    ",query(x-z,y-z,x+z,y+z));
                }
            }
        }
        return 0;
    }
    View Code

    代码:CDQ

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 9
    #define maxn 81234
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    typedef pair<PII,int>PPI;
    
    void change(int &x,int &y,int n){
        int t=x-y+n;
        y=x+y-1;
        x=t;
    }
    int Bound;
    struct node{
        int s,x,y,z,id;
        bool operator <(const node &B)const{
            if(x!=B.x)return x<B.x;
            return y<B.y;
        }    
    }Q[maxn*4],q1[maxn*4],q2[maxn*4];
    
    int Ans[maxn];
    void addnode(int s,int x,int y,int z,int id,int &tot){
        Q[++tot].s=s;
        Q[tot].x=x;Q[tot].y=y;Q[tot].z=z;
        Q[tot].id=id;
    }
    int dat[maxn];
    void add(int k,int val){
        while(k<Bound){
            dat[k]+=val;
            k+=lowbit(k);
        }
    }
    int query(int k){
        int sum=0;
        while(k>0){
            sum+=dat[k];
            k-=lowbit(k);
        }
        return sum;
    }
    void cdq(int l,int r){
        if(l==r)return;
        int mid=l+r>>1;
        cdq(l,mid);
        int l1=0,l2=0;
        for(int i=l;i<=mid;++i){
            q1[l1++]=Q[i];
        }
        for(int i=mid+1;i<=r;++i){
            q2[l2++]=Q[i];
        }
        sort(q1,q1+l1);
        sort(q2,q2+l2);
        int j=0;
        for(int i=0;i<l2;++i){
            if(q2[i].s==1)continue;
            while(j<l1 &&(q1[j].s==2 || q1[j].x<=q2[i].x)){
                if(q1[j].s==1)add(q1[j].y,q1[j].z);
                j++;
            }
            Ans[q2[i].id]+=query(q2[i].y)*q2[i].z;
        }
        for(int i=j-1;i>=0;--i)
        if(q1[i].s==1)add(q1[i].y,-q1[i].z);
        cdq(mid+1,r);
    }
    
    int main()
    {
        int n,m;
        while(1){
            scanf("%d",&n);
            if(n==0)break;
            scanf("%d",&m);
            Bound=n*2+1;
            int s,x,y,z;
            int a,b,c,d;
            int tot=0;
            for(int i=1;i<=m;++i){
                scanf("%d%d%d%d",&s,&x,&y,&z);
                change(x,y,n);
                if(s==1){
                    addnode(s,x,y,z,i,tot);
                }
                else{
                    a=x-z;b=y-z;c=x+z;d=y+z;
                    a=max(a,1);b=max(b,1);
                    c=min(Bound-1,c);
                    d=min(Bound-1,d);
                    addnode(s,c,d,1,i,tot);
                    addnode(s,a-1,b-1,1,i,tot);
                    addnode(s,c,b-1,-1,i,tot);
                    addnode(s,a-1,d,-1,i,tot);
                }
            }
            memset(Ans,0,sizeof(Ans));
            cdq(1,tot);
            for(int i=1;i<=tot;++i){
                if(Q[i].s==2){
                    printf("%d
    ",Ans[Q[i].id]);
                    i+=3;
                }
            }
        }
        return 0;
    }
    View Code

    6.隐藏题目

    这是一道高神出的题目。因为这题目前还未出现过,所以这部分题解不公开。

    /*

    (------这是一个坑------)

    */

    //填坑运动

    6.Pinball Game 4D (shuoj 1959)

             这道是4维的题;首先第一维很好处理,时间顺序。第二维按照X轴排序,接下来就原问题了。因为还剩下两维不能处理。所以这个时候就需要cdq套cdq了,额外记录一个值,表示要遵循的先前的条件。

     代码:

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <bitset>
    #include <cctype>
    #define NINF -0x3f3f3f3f
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A))
    #define IT iterator
    #define M_PI 3.14159265358979323846
    #define _ ios_base::sync_with_stdio(0);cin.tie(0);
    #define X first
    #define Y second
    #define MAX_V 10101
    #define maxn 40009
    #define lowbit(X) (X & (-X))
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef pair<int,ll>PII;
    typedef pair<PII,int>PPI;
    
    int Fu[maxn*3];
    ll Num[maxn];
    int D[maxn];
    const ll MOD=(1e9+7);
    struct node{
        int x,y,z,id;
    }A[maxn];
    struct node2{
        int x,y,z,id,sign;
        bool operator<(const node2&B)const{
            if(x!=B.x) return x<B.x;
            if(y!=B.y) return y<B.y;
            if(z!=B.z) return z<B.z;
            return id<B.id;
        }
    }q1[maxn];
    
    struct node3{
        int x,y,z,id,sign,before;
        bool operator<(const node3&B)const{
            if(y!=B.y) return y<B.y;
            if(z!=B.z) return z<B.z;
            return id<B.id;
        }
    }q2[maxn];
    
    PII dat[maxn*3];
    void update(int k,int val,ll num){
        while(k<maxn*3){
            if(val>dat[k].X){
                dat[k].X=val;
                dat[k].Y=num;
            }
            else if(val==dat[k].X){
                dat[k].Y+=num;
                dat[k].Y%=MOD;
            }
            k+=lowbit(k);
        }
    }
    PII  query(int k){
        PII Max=MP(0,0);
        while(k>0){
            if(dat[k].X>Max.X){
                Max=dat[k];
            }
            else if(dat[k].X==Max.X){
                Max.Y+=dat[k].Y;
                Max.Y%=MOD;
            }
            k-=lowbit(k);
        }
        return Max;
    }
    void clear(int k){
        while(k<maxn*3){
            dat[k]=MP(0,0);
            k+=lowbit(k);
        }
    }
    
    void cdq2(int l,int r){
        if(l==r)return ;
        int mid=l+r>>1;
        cdq2(l,mid);
        for(int i=l;i<=r;++i){
            q2[i].x=q1[i].x;q2[i].y=q1[i].y;
            q2[i].z=q1[i].z;q2[i].id=q1[i].id;
            q2[i].sign=q1[i].sign;
            if(i<=mid)
                q2[i].before=1;
            else
                q2[i].before=0;
        }
        sort(q2+l,q2+r+1);
        for(int i=l;i<=r;++i){
            int sign=q2[i].sign;
            if(sign==0 && q2[i].before == 1){
                update(q2[i].z,D[q2[i].id],Num[q2[i].id]);
            }
            else if(sign==1 && !q2[i].before){
                PII temp=query(q2[i].z);
                if(D[q2[i].id]<temp.X+1){
                    D[q2[i].id]=temp.X+1;
                    Num[q2[i].id]=temp.Y;
                }
                else if(D[q2[i].id]==temp.X+1){
                    Num[q2[i].id]+=temp.Y;
                    Num[q2[i].id]%=MOD;
                }
            }
        }
        for(int i=l;i<=r;++i){
            if(q2[i].sign==0 && q2[i].before==1)
            clear(q2[i].z);
        }
        cdq2(mid+1,r);
    }
    
    
    void cdq(int l,int r){
        if(l==r)return;
        int mid=l+r>>1;
        cdq(l,mid);
        for(int i=l;i<=r;++i){
            q1[i].x=A[i].x;q1[i].y=A[i].y;
            q1[i].z=A[i].z;q1[i].id=i;
            if(i<=mid)q1[i].sign=0;
            else q1[i].sign=1;
        }
        sort(q1+l,q1+r+1);
        cdq2(l,r);
        cdq(mid+1,r);
    }
    
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--){
            int n;
            scanf("%d",&n);
            int tot=0;
            for(int i=1;i<=n;++i){
                scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].z);
                A[i].id=i;
                Fu[tot++]=A[i].x;
                Fu[tot++]=A[i].y;
                Fu[tot++]=A[i].z;
            }
            sort(Fu,Fu+tot);
            for(int i=1;i<=n;++i){
                D[i]=Num[i]=1;
                A[i].x=lower_bound(Fu,Fu+tot,A[i].x)-Fu+1;
                A[i].y=lower_bound(Fu,Fu+tot,A[i].y)-Fu+1;
                A[i].z=lower_bound(Fu,Fu+tot,A[i].z)-Fu+1;
            }
            cdq(1,n);
            int Max=0;
            for(int i=1;i<=n;++i){
                Max=max(Max,D[i]);            
            }
            ll sum=0;
            for(int i=1;i<=n;++i){
                if(D[i]==Max){
                    sum=sum+Num[i];
                    sum%=MOD;
                }
            }
            printf("%d %lld
    ",Max,sum);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    CRM详细介绍网址
    element上传多图片
    多图片上传WebForm
    MemCached原理
    Redis的原理
    Ninject用法详解
    SQLsugar和unity 的用法
    json中的转义字符的处理
    fiddler
    orm多表关系
  • 原文地址:https://www.cnblogs.com/baobaopangzi88/p/4820004.html
Copyright © 2020-2023  润新知