• K-D树


    一般用来解决各种二维平面的点对统计,也许一般非正解?

    没时间慢慢写了,打完这个赛季后补细节

    (绝赞咕咕中)

    建树板子(2020.2.20更新):

    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM) x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int p[DIM];
        int lb[DIM],rb[DIM];
        Node(int x=0,int y=0,int z=0)
        {
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        //创建新节点 
        void newnode(int x)
        {
            ls[x]=rs[x]=0;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        //用子节点信息更新当前节点 
        void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]),
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
            if(rs[x])
                for(int i=0;i<DIM;i++)
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]),
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
        }
        
        //建树 调用时build(root,1,n,0) 
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x) build(ls[x],l,x-1,nxt(type));
            if(x<r) build(rs[x],x+1,r,nxt(type));
            pushup(x);
        }
        
        //【tag未在建树板子中出现】
        //将某个节点激活 
        void insert(int x,int type)
        {
            if(t[x]==cur)
            {
                t[x].tag=1;
                return;
            }
            
            now=type;
            if(cur<t[x]) insert(ls[x],nxt(type));
            else insert(rs[x],nxt(type));
        }
        
        int dist(int x)
        {
            int res=0;
            for(int i=0;i<DIM;i++)
                res+=max(0,t[x].lb[i]-cur.p[i])+max(0,cur.p[i]-t[x].rb[i]);
            return res;
        }
        
        //查询距离cur最近点的距离
        //调用时为ans=INF, cur=..., mindist(ans,root)
        void mindist(int &ans,int x)
        {
            if(t[x].tag)
            {
                int res=0;
                for(int i=0;i<DIM;i++)
                    res+=abs(t[x].p[i]-cur.p[i]);
                ans=min(ans,res);
            }
            
            int u=ls[x],L=ls[x]?dist(ls[x]):INF;
            int v=rs[x],R=rs[x]?dist(rs[x]):INF;
            if(L>R)
                swap(u,v),swap(L,R);
            
            if(L<ans) mindist(ans,u);
            if(R<ans) mindist(ans,v);
        }
        
        //【val,sum未在建树板子中出现】 
        //用两个儿子更新当前节点的值与和 
        inline void update(int x)
        {
            t[x].sum=t[x].val;
            if(ls[x]) t[x].sum+=t[ls[x]].sum;
            if(rs[x]) t[x].sum+=t[rs[x]].sum;
        }
        
        //查询某个子矩形内的和(注意坐标有可能爆int) 
        //注意l,r为行 u,d为列 
        ll query(int x,int l,int r,int u,int d)
        {
            if(t[x].rb[0]<l || t[x].lb[0]>r || t[x].rb[1]<u || t[x].lb[1]>d)
                return 0;
            if(t[x].lb[0]>=l && t[x].rb[0]<=r && t[x].lb[1]>=u && t[x].rb[1]<=d)
                return t[x].sum;
            
            ll res=0;
            if(t[x].p[0]>=l && t[x].p[0]<=r && t[x].p[1]>=u && t[x].p[1]<=d)
                res+=t[x].val;
            
            if(ls[x]) res+=query(ls[x],l,r,u,d);
            if(rs[x]) res+=query(rs[x],l,r,u,d);
            return res;
        }
    };
    View Code

    最近点对模板题:BZOJ 2648 (SJY摆棋子)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    const int INF=1<<30;
    const int N=1000005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int tag,p[DIM];
        int lb[DIM],rb[DIM];
    //需要根据维数自定义 
        Node(int x=0,int y=0,int z=0)
        {
            p[0]=x,p[1]=y,tag=z;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    Node a[N];
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].tag=cur.tag;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(a+l,a+x,a+r+1);
            
            cur=a[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
        }
        
        void insert(int x,int type)
        {
            if(t[x]==cur)
            {
                t[x].tag=1;
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],nxt(type));
            else
                insert(rs[x],nxt(type));
        }
        
        inline int dist(int x)
        {
            int res=0;
            for(int i=0;i<DIM;i++)
                res+=max(0,t[x].lb[i]-cur.p[i])+max(0,cur.p[i]-t[x].rb[i]);
            return res;
        }
        
        inline void mindist(int &ans,int x)
        {
            if(t[x].tag)
            {
                int res=0;
                for(int i=0;i<DIM;i++)
                    res+=abs(t[x].p[i]-cur.p[i]);
                ans=min(ans,res);
            }
            
            int u=ls[x],L=ls[x]?dist(ls[x]):INF;
            int v=rs[x],R=rs[x]?dist(rs[x]):INF;
            if(L>R)
                swap(u,v),swap(L,R);
            
            if(L<ans)
                mindist(ans,u);
            if(R<ans)
                mindist(ans,v);
        }
    };
    
    KDTree tree;
    int t[N],x[N],y[N];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            a[i].tag=1;
            read(a[i].p[0]),read(a[i].p[1]);
        }
        for(int i=1;i<=m;i++)
        {
            read(t[i]),read(x[i]),read(y[i]);
            if(t[i]==1)
                a[++n]=Node(x[i],y[i],0);
        }
        
        tree.build(root,1,n,0);
        
        for(int i=1;i<=m;i++)
        {
            tree.cur=Node(x[i],y[i]);
            if(t[i]==1)
                tree.insert(root,0);
            else
            {
                int ans=INF;
                tree.mindist(ans,root);
                out(ans),putchar('
    ');
            }
        }
        return 0;
    }
    View Code

    差不多的一道题,多一个删除:HDU 2966 ($In case of failure$)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(ll x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    const ll INF=1LL<<60;
    const int N=100005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int tag,p[DIM];
        int lb[DIM],rb[DIM];
    //需要根据维数自定义 
        Node(int x=0,int y=0,int z=0)
        {
            p[0]=x,p[1]=y,tag=z;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    Node a[N];
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].tag=cur.tag;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(a+l,a+x,a+r+1);
            
            cur=a[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
        }
        
        void rev(int x,int type)
        {
            if(t[x]==cur)
            {
                t[x].tag^=1;
                return;
            }
            
            now=type;
            if(cur<t[x])
                rev(ls[x],nxt(type));
            else
                rev(rs[x],nxt(type));
        }
        
        inline ll sq(ll x)
        {
            return x*x;
        }
        
        inline ll dist(int x)
        {
            ll res=0;
            for(int i=0;i<DIM;i++)
                res+=sq(max(0,t[x].lb[i]-cur.p[i]))+sq(max(0,cur.p[i]-t[x].rb[i]));
            return res;
        }
        
        inline void mindist(ll &ans,int x)
        {
            if(t[x].tag)
            {
                ll res=0;
                for(int i=0;i<DIM;i++)
                    res+=sq(abs(t[x].p[i]-cur.p[i]));
                ans=min(ans,res);
            }
            
            int u=ls[x];
            ll L=ls[x]?dist(ls[x]):INF;
            int v=rs[x];
            ll R=rs[x]?dist(rs[x]):INF;
            if(L>R)
                swap(u,v),swap(L,R);
            
            if(L<ans)
                mindist(ans,u);
            if(R<ans)
                mindist(ans,v);
        }
    };
    
    KDTree tree;
    int x[N],y[N];
    
    int main()
    {
        int T;
        read(T);
        while(T--)
        {
    
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            read(x[i]),read(y[i]);
            a[i]=Node(x[i],y[i],1);
            tree.ls[i]=tree.rs[i]=0;
        }
        
        tree.build(root,1,n,0);
        
        for(int i=1;i<=n;i++)
        {
            tree.cur=Node(x[i],y[i]);
            tree.rev(root,0);
            
            ll ans=INF;
            tree.mindist(ans,root);
            out(ans),putchar('
    ');
            
            tree.rev(root,0);
        }
    
        }
        return 0;
    }
    View Code

    求第$k$远点对:Luogu P4357 ($K$远点对,$CQOI2016$)

    由于$k$很小,所以不妨对于每个点求$k$次最远点,每求完一次就把最远点删掉;在求完$k$次后再全部恢复

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    typedef pair<ll,ll> pii;
    
    inline void read(ll &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(ll x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    const ll INF=-1+(1LL<<61)+(1LL<<61);
    const int N=100005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int tag;
        ll p[DIM];
        ll lb[DIM],rb[DIM];
        Node(ll x=0,ll y=0,int z=0)
        {
            p[0]=x,p[1]=y,tag=z;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].tag=cur.tag;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
        }
        
        void modify(int x,int dlt,int type)
        {
            if(t[x]==cur)
            {
                t[x].tag+=dlt;
                return;
            }
            
            now=type;
            if(cur<t[x])
                modify(ls[x],dlt,nxt(type));
            else
                modify(rs[x],dlt,nxt(type));
        }
        
        inline ll dist(int x)
        {
            ll res=0;
            for(int i=0;i<DIM;i++)
            {
                ll dmax=max(abs(t[x].lb[i]-cur.p[i]),abs(t[x].rb[i]-cur.p[i]));
                res+=dmax*dmax;
            }
            return res;
        }
        
        inline void query(ll &ans,int &pos,int x)
        {
            if(t[x].tag>0)
            {
                ll res=0;
                for(int i=0;i<DIM;i++)
                    res+=(t[x].p[i]-cur.p[i])*(t[x].p[i]-cur.p[i]);
                if(res>ans)
                {
                    ans=res;
                    pos=x;
                }
            }
            
            int u=ls[x];
            ll L=ls[x]?dist(ls[x]):0LL;
            int v=rs[x];
            ll R=rs[x]?dist(rs[x]):0LL;
            if(L<R)
                swap(u,v),swap(L,R);
            
            if(L>ans)
                query(ans,pos,u);
            if(R>ans)
                query(ans,pos,v);
        }
    };
    
    KDTree tree;
    int n,k;
    pii p[N];
    int num[N];
    
    ll a[205];
    
    inline bool cmp(ll x,ll y)
    {
        return x>y;
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            read(p[i].first),read(p[i].second);
        
        sort(p+1,p+n+1);
        
        int m=unique(p+1,p+n+1)-p-1;
        for(int i=1;i<=n;i++)
        {
            int pos=lower_bound(p+1,p+n+1,p[i])-p;
            num[pos]++;
        }
        for(int i=1;i<=m;i++)
            tree.t[i]=Node(p[i].first,p[i].second,num[i]);
        
        tree.build(root,1,m,0);
        
        for(int i=1;i<=m;)
        {
            tree.cur=tree.t[i];
            tree.modify(root,-1,0);
            
            vector<int> v;
            for(int j=1;j<=k && i+j<=n;j++)
            {
                int pos=-1;
                ll ans=a[k];
                
                tree.cur=tree.t[i];
                tree.query(ans,pos,root);
                if(pos<0)
                    break;
                
                v.push_back(pos);
                tree.cur=tree.t[pos];
                tree.modify(root,-1,0);
                a[k+v.size()]=ans;
            }
            
            sort(a+1,a+k+v.size()+1,cmp);
            
            for(int j=0;j<v.size();j++)
            {
                tree.cur=tree.t[v[j]];
                tree.modify(root,1,0);
            }
            
            if(tree.t[i].tag<1)
                i++;
        }
        
        out(a[k]),putchar('
    ');
        return 0;
    }
    View Code

    挺巧妙的题目,将树上问题通过dfs序转成平面上问题:BZOJ 4154 ($Generating Synergy$,$Ipsc2015$)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    typedef long long ll;
    const int MOD=1000000007;
    const int INF=1<<30;
    const int N=100005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int c,tag,p[DIM];
        int lb[DIM],rb[DIM];
    //需要根据维数自定义 
        Node(int x=0,int y=0,int z=0)
        {
            p[0]=x,p[1]=y,tag=z;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    Node a[N];
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].tag=cur.tag;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        inline void pushdown(int x)
        {
            if(!t[x].tag)
                return;
            
            t[x].c=t[x].tag;
            if(ls[x])
                t[ls[x]].tag=t[x].tag;
            if(rs[x])
                t[rs[x]].tag=t[x].tag;
            t[x].tag=0;
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(a+l,a+x,a+r+1);
            
            cur=a[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
        }
        
        int query(int x,int type)
        {
            pushdown(x);
            if(t[x]==cur)
                return t[x].c;
            
            now=type;
            if(cur<t[x])
                return query(ls[x],nxt(type));
            else
                return query(rs[x],nxt(type));
        }
        
        void modify(int x,int l,int r,int u,int d,int color)
        {
            pushdown(x);
            if(t[x].rb[0]<l || t[x].lb[0]>r || t[x].rb[1]<u || t[x].lb[1]>d)
                return;
            if(t[x].lb[0]>=l && t[x].rb[0]<=r && t[x].lb[1]>=u && t[x].rb[1]<=d)
            {
                t[x].tag=color;
                return;
            }
            
            if(t[x].p[0]>=l && t[x].p[0]<=r && t[x].p[1]>=u && t[x].p[1]<=d)
                t[x].c=color;
            if(ls[x])
                modify(ls[x],l,r,u,d,color);
            if(rs[x])
                modify(rs[x],l,r,u,d,color);
        }
    };
    
    KDTree tree;
    
    int n,c,m;
    int fa[N];
    vector<int> v[N];
    
    int dep[N];
    int tot,st[N],ed[N];
    
    void dfs(int x)
    {
        st[x]=++tot;
        dep[x]=dep[fa[x]]+1;
        
        for(int i=0;i<v[x].size();i++)
            dfs(v[x][i]);
        
        ed[x]=tot;
    }
    
    int main()
    {
        int T;
        read(T);
        while(T--)
        {
            for(int i=1;i<=n;i++)
            {
                v[i].clear();
                tree.ls[i]=tree.rs[i]=0;
            }
            
            read(n),read(c),read(m);
            for(int i=2;i<=n;i++)
            {
                int x;
                read(x);
                fa[i]=x;
                v[x].push_back(i);
            }
            
            dfs(1);
            
            for(int i=1;i<=n;i++)
                a[i]=Node(st[i],dep[i],1);
            
            tree.build(root,1,n,0);
            
            ll ans=0;
            for(int i=1;i<=m;i++)
            {
                int x,y,z;
                read(x),read(y),read(z);
                
                if(z==0)
                {
                    tree.cur=Node(st[x],dep[x]);
                    int res=tree.query(root,0);
    //                printf("res=%d
    ",res);
                    ans=(ans+1LL*i*res)%MOD;
                }
                else
                    tree.modify(root,st[x],ed[x],dep[x],dep[x]+y,z);
            }
            
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    也可以处理单点修改区间查询:Luogu P4148 (简单题)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    typedef pair<int,int> pii;
    const int INF=1<<30;
    const int N=200005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int val,sum,p[DIM];
        int lb[DIM],rb[DIM];
    //需要根据维数自定义 
        Node(int x=0,int y=0,int z=0)
        {
            val=z;
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int sz,ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        inline void update(int x)
        {
            t[x].sum=t[x].val;
            if(ls[x])
                t[x].sum+=t[ls[x]].sum;
            if(rs[x])
                t[x].sum+=t[rs[x]].sum;
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            update(x);
            pushup(x);
        }
        
        void insert(int &x,int dlt,int type)
        {
            if(!x)
            {
                x=++sz;
                newnode(x);
            }
            if(t[x]==cur)
            {
                t[x].val+=dlt;
                update(x);
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],dlt,nxt(type));
            else
                insert(rs[x],dlt,nxt(type));
            
            update(x);
            pushup(x);
        }
        
        int query(int x,int l,int r,int u,int d)
        {
            if(t[x].rb[0]<l || t[x].lb[0]>r || t[x].rb[1]<u || t[x].lb[1]>d)
                return 0;
            if(t[x].lb[0]>=l && t[x].rb[0]<=r && t[x].lb[1]>=u && t[x].rb[1]<=d)
                return t[x].sum;
            
            int res=0;
            if(t[x].p[0]>=l && t[x].p[0]<=r && t[x].p[1]>=u && t[x].p[1]<=d)
                res+=t[x].val;
            if(ls[x])
                res+=query(ls[x],l,r,u,d);
            if(rs[x])
                res+=query(rs[x],l,r,u,d);
            return res;
        }
    };
    
    KDTree tree;
    
    int main()
    {
        int n;
        read(n);
        
        int last_ans=0;
        while(1)
        {
            int op,l,r,u,d;
            read(op);
            if(op==3)
                break;
            
            if(op==1)
            {
                read(l),read(r),read(u);
                l^=last_ans,r^=last_ans,u^=last_ans;
                tree.cur=Node(l,r);
                
                tree.insert(root,u,0);
                if(tree.sz%700==0)
                    tree.build(root,1,tree.sz,0);
            }
            else
            {
                read(l),read(u),read(r),read(d);
                l^=last_ans,r^=last_ans,u^=last_ans,d^=last_ans;
                
                last_ans=tree.query(root,l,r,u,d);
                out(last_ans);
                putchar('
    ');
            }
        }
        return 0;
    }
    View Code

    同样是区间查询:Luogu P3810 【模板】三维偏序)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    typedef long long ll;
    const int INF=1<<30;
    const int N=100005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int val,sum,p[DIM];
        int lb[DIM],rb[DIM];
        Node(int x=0,int y=0)
        {
            val=sum=0;
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].val=t[x].sum=0;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        inline void update(int x)
        {
            t[x].sum=t[x].val;
            if(ls[x])
                t[x].sum+=t[ls[x]].sum;
            if(rs[x])
                t[x].sum+=t[rs[x]].sum;
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            update(x);
            pushup(x);
        }
        
        void insert(int x,int type)
        {
            if(t[x]==cur)
            {
                t[x].val++;
                update(x);
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],nxt(type));
            else
                insert(rs[x],nxt(type));
            
            update(x);
        }
        
        int query(int x)
        {
            if(t[x].lb[0]>cur.p[0] || t[x].lb[1]>cur.p[1])
            return 0;
            if(t[x].rb[0]<=cur.p[0] && t[x].rb[1]<=cur.p[1])
            return t[x].sum;
            
            int res=0;
            if(t[x].p[0]<=cur.p[0] && t[x].p[1]<=cur.p[1])
            res+=t[x].val;
            if(ls[x])
                res+=query(ls[x]);
            if(rs[x])
                res+=query(rs[x]);
            return res;
        }
    };
    
    KDTree tree;
    
    int n,m;
    struct tri
    {
        int p[3];
    }a[N];
    inline bool operator <(const tri &A,const tri &B)
    {
        for(int i=0;i<3;i++)
            if(A.p[i]!=B.p[i])
                return A.p[i]<B.p[i];
        return false;
    }
    inline bool operator ==(tri &A,tri &B)
    {
        for(int i=0;i<3;i++)
            if(A.p[i]!=B.p[i])
                return false;
        return true;
    }
    
    int ans[N];
    
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<3;j++)
                read(a[i].p[j]);
            tree.t[i]=Node(a[i].p[1],a[i].p[2]);
        }
        
        sort(a+1,a+n+1);
        tree.build(root,1,n,0);
        
        for(int i=1,j;i<=n;i=j)
        {
            j=i;
            while(j<=n && a[i]==a[j])
                j++;
            
            for(int k=0;k<2;k++)
                tree.cur.p[k]=a[i].p[k+1];
            for(int k=i;k<j;k++)
                tree.insert(root,0);
            
            int res=tree.query(root);
            ans[res]+=j-i;
        }
        for(int i=1;i<=n;i++)
            out(ans[i]),putchar('
    ');
        return 0;
    }        
    View Code

    稍微麻烦点的题目:HDU 5994 ($Generator and Monitor$,$2016ICPC$青岛)

    如果线段树上的能想清楚,KD树上的也就差不多了

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    const int INF=1<<30;
    const int N=200005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int p[DIM];
        int lb[DIM],rb[DIM];
        int id,val,tag,minv,minp;
        Node(int x=0,int y=0,int z=0,int w=0)
        {
            p[0]=x,p[1]=y,id=z,val=w;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int sz,fa[N],ls[N],rs[N];
        
        inline void newnode(int x,int f)
        {
            t[x].tag=0;
            t[x].minp=x;
            t[x].id=cur.id;
            t[x].val=t[x].minv=cur.val;
            
            fa[x]=f;
            ls[x]=rs[x]=0;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        inline void pushdown(int x)
        {
            if(!t[x].tag)
                return;
            
            if(ls[x])
            {
                t[ls[x]].val+=t[x].tag;
                t[ls[x]].tag+=t[x].tag;
                t[ls[x]].minv+=t[x].tag;
            }
            if(rs[x])
            {
                t[rs[x]].val+=t[x].tag;
                t[rs[x]].tag+=t[x].tag;
                t[rs[x]].minv+=t[x].tag;
            }
            t[x].tag=0;
        }
        
        void pushall(int x)
        {
            pushdown(x);
            if(ls[x])
                pushall(ls[x]);
            if(rs[x])
                pushall(rs[x]);
        }
        
        inline void update(int x)
        {
            t[x].minp=x;
            t[x].minv=t[x].val;
            
            if(ls[x] && t[ls[x]].minv<t[x].minv)
            {
                t[x].minv=t[ls[x]].minv;
                t[x].minp=t[ls[x]].minp;
            }
            if(rs[x] && t[rs[x]].minv<t[x].minv)
            {
                t[x].minv=t[rs[x]].minv;
                t[x].minp=t[rs[x]].minp;
            }
        }
        
        void build(int &x,int l,int r,int type,int f)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x,f);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type),x);
            if(x<r)
                build(rs[x],x+1,r,nxt(type),x);
            
            pushup(x);
            update(x);
        }
        
        void insert(int &x,int type,int f)
        {
            pushdown(x);
            if(!x)
            {
                x=++sz;
                newnode(x,f);
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],nxt(type),x);
            else
                insert(rs[x],nxt(type),x);
            
            pushup(x);
            update(x);
        }
        
        void modify(int x,int y)
        {
            pushdown(x);
            if(t[x].lb[0]>y || t[x].rb[1]<y)
                return;
            if(t[x].rb[0]<=y && t[x].lb[1]>=y)
            {
                t[x].val--;
                t[x].tag=-1;
                pushdown(x);
                update(x);
                return;
            }
            
            if(t[x].p[0]<=y && t[x].p[1]>=y)
                t[x].val--;
            if(ls[x])
                modify(ls[x],y);
            if(rs[x])
                modify(rs[x],y);
            update(x);
        }
        
        void rev(int x)
        {
            vector<int> v;
            
            int cur=x;
            while(cur)
            {
                v.push_back(cur);
                cur=fa[cur];
            }
            
            for(int i=v.size()-1;i>=0;i--)
                pushdown(v[i]);
            
            t[x].val=INF;
            for(int i=0;i<v.size();i++)
                update(v[i]);
        }
    };
    
    KDTree tree;
    
    int n,m;
    
    int main()
    {
        int T;
        read(T);
        for(int kase=1;kase<=T;kase++)
        {
            printf("Case #%d:
    ",kase);
            for(int i=1;i<=tree.sz;i++)
                tree.ls[i]=tree.rs[i]=tree.fa[i]=0;
            root=tree.sz=0;
            
            int xorsum=0;
            read(n),read(m);
            for(int i=1;i<=n;i++)
            {
                char op=getchar();
                while(op<'A' || op>'Z')
                    op=getchar();
                
                int x,y,z;
                if(op=='C')
                {
                    read(x),read(y),read(z);
                    
                    tree.cur=Node(x,y,i,z);
                    tree.insert(root,0,0);
                    
                    if(tree.sz%1200==0)
                    {
                        tree.pushall(root);
                        tree.build(root,1,tree.sz,0,0);
                    }
                }
                else
                {
                    if(!root)
                        continue;
                    
                    read(x);
                    x^=xorsum;
                    
                    tree.modify(root,x);
                    
                    vector<int> v;
                    while(!tree.t[root].minv)
                    {
                        int pos=tree.t[root].minp;
                        v.push_back(tree.t[pos].id);
                        
                        tree.rev(pos);
                    }
                    
                    sort(v.begin(),v.end());
                    
                    if(v.size()) 
                        out(i);
                    for(int j=0;j<v.size();j++)
                    {
                        xorsum^=v[j];
                        putchar(' '),out(v[j]);
                    }
                    if(v.size()) 
                        putchar('
    ');
                }
            }
        }
        return 0;
    }
    View Code

    一些总结(主要是卡常):

    1. 对于最近点对,查询时先访问 边界离查询点更近 的树节点,能卡掉$2 ext{~}4$倍常数

    2. 如果题目没有强制要求在线,最好离线后建树;否则考虑定期重构(单次重构$nlogn$,单次查询$max(sqrt{n},frac{n}{size})$,稍微计算一下即可)

    3. 复杂度是$O(n^{frac{2k-1}{k}})$,所以维数越高时间复杂度越差;有时候可以像三维偏序一样,通过一些外部的处理去掉一个维度


    如果遇到的话,慢慢更一些题目

    看到三元组其实就可以往这方面想了:HDU 5517 ($Triple$,$2016ICPC$沈阳)

    正解是二维树状数组?那没事了

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    struct tri
    {
        int x,y,z,cnt;
        tri(int a=0,int b=0,int c=0,int d=0)
        {
            x=a,y=b,z=c,cnt=d;
        }
    };
    
    inline bool operator <(const tri &X,const tri &Y)
    {
        if(X.x!=Y.x)
            return X.x<Y.x;
        if(X.y!=Y.y)
            return X.y<Y.y;
        if(X.z!=Y.z)
            return X.z<Y.z;
        return false;
    }
    
    inline bool operator ==(const tri &X,const tri &Y)
    {
        return (X.x==Y.x && X.y==Y.y && X.z==Y.z);
    }
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(int x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    typedef pair<int,int> pii;
    const int INF=1<<30;
    const int N=100005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int tag,p[DIM];
        int lb[DIM],rb[DIM];
        Node(int x=0,int y=0)
        {
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].tag=cur.tag;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
        }
        
        void insert(int x,int type)
        {
            if(t[x]==cur)
            {
                t[x].tag=1;
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],nxt(type));
            else
                insert(rs[x],nxt(type));
        }
        
        bool query(int x,int l,int r)
        {
            if(t[x].rb[0]<l || t[x].rb[1]<r)
                return false;
            if(t[x].tag && t[x].p[0]>=l && t[x].p[1]>=r)
                return true;
            
            bool res=false;
            if(ls[x])
                res|=query(ls[x],l,r);
            if(rs[x])
                res|=query(rs[x],l,r);
            return res;
        }
    };
    
    KDTree tree;
    
    int n,m,sz;
    vector<int> vl[N];
    vector<pii> vr[N];
    
    tri point[N];
    
    int main()
    {
        int T;
        read(T);
        for(int kase=1;kase<=T;kase++)
        {
            for(int i=1;i<=100000;i++)
                vl[i].clear(),vr[i].clear();
            
            read(n),read(m);
            for(int i=1;i<=n;i++)
            {
                int a,b;
                read(a),read(b);
                vl[b].push_back(a);
            }
            for(int i=1;i<=m;i++)
            {
                int c,d,e;
                read(c),read(d),read(e);
                vr[e].push_back(pii(c,d));
            }
            
            sz=0;
            for(int i=1;i<=100000;i++)
            {
                if(vl[i].size()==0)
                    continue;
                
                sort(vl[i].begin(),vl[i].end());
                int amax=vl[i].back(),cnt=0;
                for(int j=vl[i].size()-1;j>=0;j--)
                    if(vl[i][j]==amax)
                        cnt++;
                
                for(int j=0;j<vr[i].size();j++)
                    point[++sz]=tri(amax,vr[i][j].first,vr[i][j].second,cnt);
            }
            
            sort(point+1,point+sz+1);
            
            for(int i=1;i<=sz;i++)
            {
                tree.t[i].tag=0;
                tree.t[i].p[0]=point[i].y;
                tree.t[i].p[1]=point[i].z;
            }
            
            tree.build(root,1,sz,0);
            
            int ans=0;
            for(int i=sz;i>=1;)
            {
                int j=i;
                while(j>=1 && point[j]==point[i])
                    j--;
                
                int add=i-j;
                if(!tree.query(root,point[i].y,point[i].z))
                    ans+=add*point[i].cnt;
                
                tree.cur=Node(point[i].y,point[i].z);
                tree.insert(root,0);
                
                i=j;
            }
            
            printf("Case #%d: %d
    ",kase,ans);
        }
        return 0;
    }
    View Code

    才反应过来KD树能代替动态主席树:计蒜客T42400 ($Paper Grading$,$2019ICPC$南京)

    也是一种思路吧,也可以避免离散化

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    struct TrieNode
    {
        bool end;
        int to[26];
        TrieNode()
        {
            end=false;
            memset(to,0,sizeof(to));
        }
    };
    
    const int N=200005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int val,sum,p[DIM];
        int lb[DIM],rb[DIM];
        Node(int x=0,int y=0,int z=0)
        {
            val=z;
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N*10];
        int sz,ls[N*10],rs[N*10];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        inline void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        inline void update(int x)
        {
            t[x].sum=t[x].val;
            if(ls[x])
                t[x].sum+=t[ls[x]].sum;
            if(rs[x])
                t[x].sum+=t[rs[x]].sum;
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            update(x);
            pushup(x);
        }
        
        void insert(int &x,int dlt,int type)
        {
            if(!x)
            {
                x=++sz;
                newnode(x);
            }
            if(t[x]==cur)
            {
                t[x].val+=dlt;
                update(x);
                return;
            }
            
            now=type;
            if(cur<t[x])
                insert(ls[x],dlt,nxt(type));
            else
                insert(rs[x],dlt,nxt(type));
            
            update(x);
            pushup(x);
        }
        
        int query(int x,int l,int r,int u,int d)
        {
            if(t[x].rb[0]<l || t[x].lb[0]>r || t[x].rb[1]<u || t[x].lb[1]>d)
                return 0;
            if(t[x].lb[0]>=l && t[x].rb[0]<=r && t[x].lb[1]>=u && t[x].rb[1]<=d)
                return t[x].sum;
            
            int res=0;
            if(t[x].p[0]>=l && t[x].p[0]<=r && t[x].p[1]>=u && t[x].p[1]<=d)
                res+=t[x].val;
            if(ls[x])
                res+=query(ls[x],l,r,u,d);
            if(rs[x])
                res+=query(rs[x],l,r,u,d);
            return res;
        }
    };
    
    int n,m,len;
    string s[N];
    
    int top=0;
    TrieNode trie[N];
    
    int insert(int x)
    {
        int cur=0;
        for(int i=0;i<s[x].length();i++)
        {
            int &nxt=trie[cur].to[s[x][i]-'a'];
            if(nxt==0)
                nxt=++top;
            cur=nxt;
        }
        trie[cur].end=true;
        return cur;
    }
    
    int tot;
    int st[N],ed[N];
    
    void label(int x)
    {
        if(trie[x].end)
            st[x]=ed[x]=++tot;
        
        for(int i=0;i<26;i++)
        {
            int nxt=trie[x].to[i];
            if(nxt)
            {
                label(nxt);
            
                if(!st[x])
                    st[x]=st[nxt];
                ed[x]=ed[nxt];
            }
        }
    }
    
    int sz;
    KDTree tree;
    
    int x[N],y[N];
    int K[N],L[N],R[N];
    int opt[N],dfn[N],val[N];
    string q[N];
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>s[i];
            val[i]=i;
            insert(i);
        }
        
        label(0);
        
        for(int i=1;i<=n;i++)
        {
            int cur=0;
            for(int j=0;j<s[i].length();j++)
                cur=trie[cur].to[s[i][j]-'a'];
            
            dfn[i]=st[cur];
            tree.t[++sz]=Node(dfn[i],i,1);
        }
        
        for(int i=1;i<=m;i++)
        {
            cin>>opt[i];
            if(opt[i]==1)
            {
                cin>>x[i]>>y[i];
                
                swap(val[x[i]],val[y[i]]);
                tree.t[++sz]=Node(dfn[val[x[i]]],x[i],0);
                tree.t[++sz]=Node(dfn[val[y[i]]],y[i],0);
            }
            else
                cin>>q[i]>>K[i]>>L[i]>>R[i];
        }
        
        tree.build(root,1,sz,0);
        
        for(int i=1;i<=n;i++)
            val[i]=i;
        for(int i=1;i<=m;i++)
        {
            if(opt[i]==1)
            {
                tree.cur=Node(dfn[val[x[i]]],x[i]);
                tree.insert(root,-1,0);
                tree.cur=Node(dfn[val[y[i]]],y[i]);
                tree.insert(root,-1,0);
                
                swap(val[x[i]],val[y[i]]);
                tree.cur=Node(dfn[val[x[i]]],x[i]);
                tree.insert(root,1,0);
                tree.cur=Node(dfn[val[y[i]]],y[i]);
                tree.insert(root,1,0);
            }
            else
            {
                int cur=0;
                for(int j=0;j<K[i];j++)
                {
                    int nxt=trie[cur].to[q[i][j]-'a'];
                    if(!nxt)
                    {
                        cur=0;
                        break;
                    }
                    else
                        cur=nxt;
                }
                
                if(cur==0 && K[i]!=0)
                    cout<<0<<'
    ';
                else
                    cout<<tree.query(root,st[cur],ed[cur],L[i],R[i])<<'
    ';
            }
        }
        return 0;
    }
    View Code

    还是代替动态主席树:计蒜客T42574 ($Yuuki and a problem$,$2019ICPC$徐州)

    不过这题出的一个问题是KD树上的坐标范围可能超过int,所以需要取min来限制

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    const int DIM=2;
    const int N=200005;
    
    inline int nxt(int x){
        if(++x==DIM) x=0;
        return x;
    }
    
    int now;
    struct Node{
        ll val,sum;
        int p[DIM];
        int lb[DIM],rb[DIM];
        Node(int x=0,int y=0,ll z=0) {p[0]=x,p[1]=y,val=z,sum=0;}
    };
    inline bool operator <(const Node &X,const Node &Y){
        int i=now;
        if(X.p[i]!=Y.p[i]) return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i]) return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y){
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i]) return false;
        return true;
    }
    
    int root;
    struct KDTree{
        Node cur,t[N<<1];
        int ls[N<<1],rs[N<<1];
        inline void newnode(int x){
            ls[x]=rs[x]=0;
            t[x].val=t[x].sum=cur.val;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        inline void update(int x){
            t[x].sum=t[x].val;
            if(ls[x]) t[x].sum+=t[ls[x]].sum;
            if(rs[x]) t[x].sum+=t[rs[x]].sum;
        }
        inline void pushup(int x){
            if(ls[x])
                for(int i=0;i<DIM;i++)
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]),
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
            if(rs[x])
                for(int i=0;i<DIM;i++)
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]),
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
        }
        void build(int &x,int l,int r,int type){
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1); 
            cur=t[x];
            newnode(x); 
            if(l<x) build(ls[x],l,x-1,nxt(type));
            if(x<r) build(rs[x],x+1,r,nxt(type)); 
            pushup(x);
            update(x);
        }
        void insert(int x,int dlt,int type){
            if(t[x]==cur){
                t[x].val+=dlt;
                update(x);
                return;
            } 
            now=type;
            if(cur<t[x]) insert(ls[x],dlt,nxt(type));
            else insert(rs[x],dlt,nxt(type));
            update(x);
        }
        ll query(int x,int l,int r,int u,int d)
        {
            if(t[x].rb[0]<l || t[x].lb[0]>r || t[x].rb[1]<u || t[x].lb[1]>d)
                return 0;
            if(t[x].lb[0]>=l && t[x].rb[0]<=r && t[x].lb[1]>=u && t[x].rb[1]<=d)
                return t[x].sum;
            ll res=0;
            if(t[x].p[0]>=l && t[x].p[0]<=r && t[x].p[1]>=u && t[x].p[1]<=d)
                res+=t[x].val;
            if(ls[x])
                res+=query(ls[x],l,r,u,d);
            if(rs[x])
                res+=query(rs[x],l,r,u,d);
            return res;
        }
    };
    
    KDTree tree;
    
    int n,q,sz;
    
    int a[N];
    int op[N],L[N],R[N];
    
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            tree.t[++sz]=Node(i,a[i],a[i]);
        }
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d%d",&op[i],&L[i],&R[i]);
            if(op[i]==1)
                tree.t[++sz]=Node(L[i],R[i],0);
        }
        
        tree.build(root,1,sz,0);
        
        for(int i=1;i<=q;i++)
            if(op[i]==1)
            {
                tree.cur=Node(L[i],a[L[i]]);
                tree.insert(root,-a[L[i]],0);
                tree.cur=Node(L[i],R[i]);
                tree.insert(root,R[i],0);
                a[L[i]]=R[i];
            }
            else
            {
                ll x=0,res=0;
                while(1)
                {
                    res=tree.query(root,L[i],R[i],1,min(x+1,(ll)N));
                    if(res==x)
                        break;
                    x=res;
                }
                printf("%lld
    ",x+1);
            }
        return 0;
    }
    View Code

    Nowcoder 4120I  ($Practice for KD Tree$,$2020 Wannafly Winter Camp$)

    结果现场就我一个是KD树艹过去的...(按照dls的意思KD树应该过不了)

    在query时记得根据$maxv$调换查询$L,R$的顺序以卡常(事实证明非常有效)

    #include <cstdio>
    #include <locale>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline void read(int &x)
    {
        x=0;
        int rev=1;
        char ch=getchar();
        while(!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            rev=-1,ch=getchar();
        while(isdigit(ch))
            x=x*10+ch-'0',ch=getchar();
        x*=rev;
    }
    
    inline void out(long long x)
    {
        if(x==0)
        {
            putchar('0');
            return;
        }
        int len=0;
        static char buff[20];
        while(x)
            buff[++len]=x%10+'0',x/=10;
        while(len)
            putchar(buff[len--]);
    }
    
    typedef long long ll;
    const int N=4000005;
    const int M=2005;
    const int DIM=2;
    
    inline int nxt(int x)
    {
        if(++x==DIM)
            x=0;
        return x;
    }
    
    int now;
    
    struct Node
    {
        int p[DIM];
        int lb[DIM],rb[DIM];
        ll val,maxv;
        
        Node(int x=0,int y=0,ll z=0)
        {
            val=maxv=z;
            p[0]=x,p[1]=y;
        }
    };
    inline bool operator <(const Node &X,const Node &Y)
    {
        int i=now;
        if(X.p[i]!=Y.p[i])
            return X.p[i]<Y.p[i];
        for(int i=nxt(now);i!=now;i=nxt(i))
            if(X.p[i]!=Y.p[i])
                return X.p[i]<Y.p[i];
        return false;
    }
    inline bool operator ==(const Node &X,const Node &Y)
    {
        for(int i=0;i<DIM;i++)
            if(X.p[i]!=Y.p[i])
                return false;
        return true;
    }
    
    int root;
    
    struct KDTree
    {
        Node cur,t[N];
        int ls[N],rs[N];
        
        inline void newnode(int x)
        {
            ls[x]=rs[x]=0;
            t[x].val=cur.val;
            t[x].maxv=cur.maxv;
            for(int i=0;i<DIM;i++)
                t[x].lb[i]=t[x].rb[i]=t[x].p[i]=cur.p[i];
        }
        
        void pushup(int x)
        {
            if(ls[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[ls[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[ls[x]].rb[i]);
                }
            if(rs[x])
                for(int i=0;i<DIM;i++)
                {
                    t[x].lb[i]=min(t[x].lb[i],t[rs[x]].lb[i]);
                    t[x].rb[i]=max(t[x].rb[i],t[rs[x]].rb[i]);
                }
        }
        
        void build(int &x,int l,int r,int type)
        {
            x=(l+r)>>1;
            now=type;
            nth_element(t+l,t+x,t+r+1);
            
            cur=t[x];
            newnode(x);
            
            if(l<x)
                build(ls[x],l,x-1,nxt(type));
            if(x<r)
                build(rs[x],x+1,r,nxt(type));
            
            pushup(x);
            update(x);
        }
        
        void update(int x)
        {
            t[x].maxv=t[x].val;
            if(ls[x])
                t[x].maxv=max(t[x].maxv,t[ls[x]].maxv);
            if(rs[x])
                t[x].maxv=max(t[x].maxv,t[rs[x]].maxv);
        }
        
        void query(int x,ll &ans)
        {
            if(t[x].maxv<=ans)
                return;
            if(t[x].rb[0]<cur.lb[0] || t[x].lb[0]>cur.rb[0])
                return;
            if(t[x].rb[1]<cur.lb[1] || t[x].lb[1]>cur.rb[1])
                return;
            if(t[x].lb[0]>=cur.lb[0] && t[x].rb[0]<=cur.rb[0] &&
                t[x].lb[1]>=cur.lb[1] && t[x].rb[1]<=cur.rb[1])
            {
                ans=max(ans,t[x].maxv);
                return;
            }
            
            if(t[x].p[0]>=cur.lb[0] && t[x].p[0]<=cur.rb[0] &&
                 t[x].p[1]>=cur.lb[1] && t[x].p[1]<=cur.rb[1])
                ans=max(ans,t[x].val);
            
            int L=ls[x],R=rs[x];
            if(t[L].maxv<t[R].maxv)
                swap(L,R);
             
            if(L)
                query(L,ans);
            if(R)
                query(R,ans);
        }
    }tree;
    
    int n,m1,m2;
    ll a[M][M];
    
    int main()
    {
        read(n),read(m1),read(m2);
        
        tree.build(root,1,n*n,0);
        
        for(int i=1;i<=m1;i++)
        {
            int x1,y1,x2,y2,w;
            read(x1),read(y1),read(x2),read(y2),read(w);
            a[x2][y2]+=w;
            a[x1-1][y2]-=w;
            a[x2][y1-1]-=w;
            a[x1-1][y1-1]+=w;
        }
        
        for(int i=2*n;i>=1;i--)
        {
            for(int j=min(n,i-1);j>=max(1,i-n);j--)
            {
                int y=j,x=i-j;
                a[x][y]+=a[x+1][y]+a[x][y+1]-a[x+1][y+1];
                tree.t[(x-1)*n+y]=Node(x,y,a[x][y]); 
            }
        }
        
        tree.build(root,1,n*n,0);
        
        for(int i=1;i<=m2;i++)
        {
            int x1,y1,x2,y2;
            read(x1),read(y1),read(x2),read(y2);
            
            tree.cur.lb[0]=x1,tree.cur.rb[0]=x2;
            tree.cur.lb[1]=y1,tree.cur.rb[1]=y2;
            
            ll ans=0;
            tree.query(root,ans);
            out(ans),putchar('
    ');
        }
        return 0;
    }
    View Code

    (完)

  • 相关阅读:
    js手写弹框和按钮显示
    Java类加载机制、双亲委派、Java类加载过程
    Java集合:HashMap必知必会
    查看oracle是否锁表
    消息队列Rabbit MQ 学习第一篇
    数据库blob图片文件,多图片打包下载
    HttpDebug下载
    将博客搬至CSDN
    android事件拦截处理机制详解
    回调函数
  • 原文地址:https://www.cnblogs.com/LiuRunky/p/K_Dimensional_Tree.html
Copyright © 2020-2023  润新知