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('\n');
        }
    }
    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('\n');
        
        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('\n');
    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\n",res);
                ans=(ans+1LL*i*res)%MOD;
            }
            else
                tree.modify(root,st[x],ed[x],dep[x],dep[x]+y,z);
        }
        
        printf("%lld\n",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('\n');
        }
    }
    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('\n');
    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:\n",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('\n');
            }
        }
    }
    return 0;
}
View Code

 

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

1. 对于最近点对,查询时先访问 边界离查询点更近 的树节点,能卡掉$2\text{~}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\n",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<<'\n';
            else
                cout<<tree.query(root,st[cur],ed[cur],L[i],R[i])<<'\n';
        }
    }
    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\n",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('\n');
    }
    return 0;
}
View Code

 

(完)

posted @ 2019-10-30 20:35  LiuRunky  阅读(306)  评论(0编辑  收藏  举报