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

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

(绝赞咕咕中)

建树板子(2020.2.20更新):

const int DIM=;

inline int nxt(int x)
{
if(++x==DIM) x=;
return x;
} int now; struct Node
{
int p[DIM];
int lb[DIM],rb[DIM];
Node(int x=,int y=,int z=)
{
p[]=x,p[]=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=;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]=;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x) build(ls[x],l,x-,nxt(type));
if(x<r) build(rs[x],x+,r,nxt(type));
pushup(x);
} //【tag未在建树板子中出现】
//将某个节点激活
void insert(int x,int type)
{
if(t[x]==cur)
{
t[x].tag=;
return;
} now=type;
if(cur<t[x]) insert(ls[x],nxt(type));
else insert(rs[x],nxt(type));
} int dist(int x)
{
int res=;
for(int i=;i<DIM;i++)
res+=max(,t[x].lb[i]-cur.p[i])+max(,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=;
for(int i=;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[]<l || t[x].lb[]>r || t[x].rb[]<u || t[x].lb[]>d)
return ;
if(t[x].lb[]>=l && t[x].rb[]<=r && t[x].lb[]>=u && t[x].rb[]<=d)
return t[x].sum; ll res=;
if(t[x].p[]>=l && t[x].p[]<=r && t[x].p[]>=u && t[x].p[]<=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;
}
};

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

#include <cstdio>
#include <locale>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std; inline void read(int &x)
{
x=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(int x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} const int INF=<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int tag,p[DIM];
int lb[DIM],rb[DIM];
//需要根据维数自定义
Node(int x=,int y=,int z=)
{
p[]=x,p[]=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=;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]=;
t[x].tag=cur.tag;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(a+l,a+x,a+r+); cur=a[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,r,nxt(type)); pushup(x);
} void insert(int x,int type)
{
if(t[x]==cur)
{
t[x].tag=;
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=;
for(int i=;i<DIM;i++)
res+=max(,t[x].lb[i]-cur.p[i])+max(,cur.p[i]-t[x].rb[i]);
return res;
} inline void mindist(int &ans,int x)
{
if(t[x].tag)
{
int res=;
for(int i=;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=;i<=n;i++)
{
a[i].tag=;
read(a[i].p[]),read(a[i].p[]);
}
for(int i=;i<=m;i++)
{
read(t[i]),read(x[i]),read(y[i]);
if(t[i]==)
a[++n]=Node(x[i],y[i],);
} tree.build(root,,n,); for(int i=;i<=m;i++)
{
tree.cur=Node(x[i],y[i]);
if(t[i]==)
tree.insert(root,);
else
{
int ans=INF;
tree.mindist(ans,root);
out(ans),putchar('\n');
}
}
return ;
}

差不多的一道题,多一个删除: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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(ll x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} const ll INF=1LL<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int tag,p[DIM];
int lb[DIM],rb[DIM];
//需要根据维数自定义
Node(int x=,int y=,int z=)
{
p[]=x,p[]=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=;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]=;
t[x].tag=cur.tag;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(a+l,a+x,a+r+); cur=a[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,r,nxt(type)); pushup(x);
} void rev(int x,int type)
{
if(t[x]==cur)
{
t[x].tag^=;
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=;
for(int i=;i<DIM;i++)
res+=sq(max(,t[x].lb[i]-cur.p[i]))+sq(max(,cur.p[i]-t[x].rb[i]));
return res;
} inline void mindist(ll &ans,int x)
{
if(t[x].tag)
{
ll res=;
for(int i=;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=;i<=n;i++)
{
read(x[i]),read(y[i]);
a[i]=Node(x[i],y[i],);
tree.ls[i]=tree.rs[i]=;
} tree.build(root,,n,); for(int i=;i<=n;i++)
{
tree.cur=Node(x[i],y[i]);
tree.rev(root,); ll ans=INF;
tree.mindist(ans,root);
out(ans),putchar('\n'); tree.rev(root,);
} }
return ;
}

求第$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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(ll x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} const ll INF=-+(1LL<<)+(1LL<<);
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int tag;
ll p[DIM];
ll lb[DIM],rb[DIM];
Node(ll x=,ll y=,int z=)
{
p[]=x,p[]=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=;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]=;
t[x].tag=cur.tag;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,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=;
for(int i=;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>)
{
ll res=;
for(int i=;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[]; inline bool cmp(ll x,ll y)
{
return x>y;
} int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
read(p[i].first),read(p[i].second); sort(p+,p+n+); int m=unique(p+,p+n+)-p-;
for(int i=;i<=n;i++)
{
int pos=lower_bound(p+,p+n+,p[i])-p;
num[pos]++;
}
for(int i=;i<=m;i++)
tree.t[i]=Node(p[i].first,p[i].second,num[i]); tree.build(root,,m,); for(int i=;i<=m;)
{
tree.cur=tree.t[i];
tree.modify(root,-,); vector<int> v;
for(int j=;j<=k && i+j<=n;j++)
{
int pos=-;
ll ans=a[k]; tree.cur=tree.t[i];
tree.query(ans,pos,root);
if(pos<)
break; v.push_back(pos);
tree.cur=tree.t[pos];
tree.modify(root,-,);
a[k+v.size()]=ans;
} sort(a+,a+k+v.size()+,cmp); for(int j=;j<v.size();j++)
{
tree.cur=tree.t[v[j]];
tree.modify(root,,);
} if(tree.t[i].tag<)
i++;
} out(a[k]),putchar('\n');
return ;
}

挺巧妙的题目,将树上问题通过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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(int x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} typedef long long ll;
const int MOD=;
const int INF=<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int c,tag,p[DIM];
int lb[DIM],rb[DIM];
//需要根据维数自定义
Node(int x=,int y=,int z=)
{
p[]=x,p[]=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=;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]=;
t[x].tag=cur.tag;
for(int i=;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=;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=;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=;
} void build(int &x,int l,int r,int type)
{
x=(l+r)>>;
now=type;
nth_element(a+l,a+x,a+r+); cur=a[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,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[]<l || t[x].lb[]>r || t[x].rb[]<u || t[x].lb[]>d)
return;
if(t[x].lb[]>=l && t[x].rb[]<=r && t[x].lb[]>=u && t[x].rb[]<=d)
{
t[x].tag=color;
return;
} if(t[x].p[]>=l && t[x].p[]<=r && t[x].p[]>=u && t[x].p[]<=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]]+; for(int i=;i<v[x].size();i++)
dfs(v[x][i]); ed[x]=tot;
} int main()
{
int T;
read(T);
while(T--)
{
for(int i=;i<=n;i++)
{
v[i].clear();
tree.ls[i]=tree.rs[i]=;
} read(n),read(c),read(m);
for(int i=;i<=n;i++)
{
int x;
read(x);
fa[i]=x;
v[x].push_back(i);
} dfs(); for(int i=;i<=n;i++)
a[i]=Node(st[i],dep[i],); tree.build(root,,n,); ll ans=;
for(int i=;i<=m;i++)
{
int x,y,z;
read(x),read(y),read(z); if(z==)
{
tree.cur=Node(st[x],dep[x]);
int res=tree.query(root,);
// 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 ;
}

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

#include <cstdio>
#include <locale>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std; inline void read(int &x)
{
x=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(int x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} typedef pair<int,int> pii;
const int INF=<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int val,sum,p[DIM];
int lb[DIM],rb[DIM];
//需要根据维数自定义
Node(int x=,int y=,int z=)
{
val=z;
p[]=x,p[]=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=;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]=;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,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[]<l || t[x].lb[]>r || t[x].rb[]<u || t[x].lb[]>d)
return ;
if(t[x].lb[]>=l && t[x].rb[]<=r && t[x].lb[]>=u && t[x].rb[]<=d)
return t[x].sum; int res=;
if(t[x].p[]>=l && t[x].p[]<=r && t[x].p[]>=u && t[x].p[]<=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=;
while()
{
int op,l,r,u,d;
read(op);
if(op==)
break; if(op==)
{
read(l),read(r),read(u);
l^=last_ans,r^=last_ans,u^=last_ans;
tree.cur=Node(l,r); tree.insert(root,u,);
if(tree.sz%==)
tree.build(root,,tree.sz,);
}
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 ;
}

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

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

稍微麻烦点的题目: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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(int x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} const int INF=<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int p[DIM];
int lb[DIM],rb[DIM];
int id,val,tag,minv,minp;
Node(int x=,int y=,int z=,int w=)
{
p[]=x,p[]=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=;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=;
t[x].minp=x;
t[x].id=cur.id;
t[x].val=t[x].minv=cur.val; fa[x]=f;
ls[x]=rs[x]=;
for(int i=;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=;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=;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=;
} 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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x,f); if(l<x)
build(ls[x],l,x-,nxt(type),x);
if(x<r)
build(rs[x],x+,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[]>y || t[x].rb[]<y)
return;
if(t[x].rb[]<=y && t[x].lb[]>=y)
{
t[x].val--;
t[x].tag=-;
pushdown(x);
update(x);
return;
} if(t[x].p[]<=y && t[x].p[]>=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()-;i>=;i--)
pushdown(v[i]); t[x].val=INF;
for(int i=;i<v.size();i++)
update(v[i]);
}
}; KDTree tree; int n,m; int main()
{
int T;
read(T);
for(int kase=;kase<=T;kase++)
{
printf("Case #%d:\n",kase);
for(int i=;i<=tree.sz;i++)
tree.ls[i]=tree.rs[i]=tree.fa[i]=;
root=tree.sz=; int xorsum=;
read(n),read(m);
for(int i=;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,,); if(tree.sz%==)
{
tree.pushall(root);
tree.build(root,,tree.sz,,);
}
}
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=;j<v.size();j++)
{
xorsum^=v[j];
putchar(' '),out(v[j]);
}
if(v.size())
putchar('\n');
}
}
}
return ;
}

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

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=,int b=,int c=,int d=)
{
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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(int x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} typedef pair<int,int> pii;
const int INF=<<;
const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int tag,p[DIM];
int lb[DIM],rb[DIM];
Node(int x=,int y=)
{
p[]=x,p[]=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=;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]=;
t[x].tag=cur.tag;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,r,nxt(type)); pushup(x);
} void insert(int x,int type)
{
if(t[x]==cur)
{
t[x].tag=;
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[]<l || t[x].rb[]<r)
return false;
if(t[x].tag && t[x].p[]>=l && t[x].p[]>=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=;kase<=T;kase++)
{
for(int i=;i<=;i++)
vl[i].clear(),vr[i].clear(); read(n),read(m);
for(int i=;i<=n;i++)
{
int a,b;
read(a),read(b);
vl[b].push_back(a);
}
for(int i=;i<=m;i++)
{
int c,d,e;
read(c),read(d),read(e);
vr[e].push_back(pii(c,d));
} sz=;
for(int i=;i<=;i++)
{
if(vl[i].size()==)
continue; sort(vl[i].begin(),vl[i].end());
int amax=vl[i].back(),cnt=;
for(int j=vl[i].size()-;j>=;j--)
if(vl[i][j]==amax)
cnt++; for(int j=;j<vr[i].size();j++)
point[++sz]=tri(amax,vr[i][j].first,vr[i][j].second,cnt);
} sort(point+,point+sz+); for(int i=;i<=sz;i++)
{
tree.t[i].tag=;
tree.t[i].p[]=point[i].y;
tree.t[i].p[]=point[i].z;
} tree.build(root,,sz,); int ans=;
for(int i=sz;i>=;)
{
int j=i;
while(j>= && 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,); i=j;
} printf("Case #%d: %d\n",kase,ans);
}
return ;
}

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

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

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; struct TrieNode
{
bool end;
int to[];
TrieNode()
{
end=false;
memset(to,,sizeof(to));
}
}; const int N=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int val,sum,p[DIM];
int lb[DIM],rb[DIM];
Node(int x=,int y=,int z=)
{
val=z;
p[]=x,p[]=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=;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]=;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,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[]<l || t[x].lb[]>r || t[x].rb[]<u || t[x].lb[]>d)
return ;
if(t[x].lb[]>=l && t[x].rb[]<=r && t[x].lb[]>=u && t[x].rb[]<=d)
return t[x].sum; int res=;
if(t[x].p[]>=l && t[x].p[]<=r && t[x].p[]>=u && t[x].p[]<=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=;
TrieNode trie[N]; int insert(int x)
{
int cur=;
for(int i=;i<s[x].length();i++)
{
int &nxt=trie[cur].to[s[x][i]-'a'];
if(nxt==)
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=;i<;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=;i<=n;i++)
{
cin>>s[i];
val[i]=i;
insert(i);
} label(); for(int i=;i<=n;i++)
{
int cur=;
for(int j=;j<s[i].length();j++)
cur=trie[cur].to[s[i][j]-'a']; dfn[i]=st[cur];
tree.t[++sz]=Node(dfn[i],i,);
} for(int i=;i<=m;i++)
{
cin>>opt[i];
if(opt[i]==)
{
cin>>x[i]>>y[i]; swap(val[x[i]],val[y[i]]);
tree.t[++sz]=Node(dfn[val[x[i]]],x[i],);
tree.t[++sz]=Node(dfn[val[y[i]]],y[i],);
}
else
cin>>q[i]>>K[i]>>L[i]>>R[i];
} tree.build(root,,sz,); for(int i=;i<=n;i++)
val[i]=i;
for(int i=;i<=m;i++)
{
if(opt[i]==)
{
tree.cur=Node(dfn[val[x[i]]],x[i]);
tree.insert(root,-,);
tree.cur=Node(dfn[val[y[i]]],y[i]);
tree.insert(root,-,); swap(val[x[i]],val[y[i]]);
tree.cur=Node(dfn[val[x[i]]],x[i]);
tree.insert(root,,);
tree.cur=Node(dfn[val[y[i]]],y[i]);
tree.insert(root,,);
}
else
{
int cur=;
for(int j=;j<K[i];j++)
{
int nxt=trie[cur].to[q[i][j]-'a'];
if(!nxt)
{
cur=;
break;
}
else
cur=nxt;
} if(cur== && K[i]!=)
cout<<<<'\n';
else
cout<<tree.query(root,st[cur],ed[cur],L[i],R[i])<<'\n';
}
}
return ;
}

还是代替动态主席树:计蒜客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=;
const int N=; inline int nxt(int x){
if(++x==DIM) x=;
return x;
} int now;
struct Node{
ll val,sum;
int p[DIM];
int lb[DIM],rb[DIM];
Node(int x=,int y=,ll z=) {p[]=x,p[]=y,val=z,sum=;}
};
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=;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]=;
t[x].val=t[x].sum=cur.val;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+);
cur=t[x];
newnode(x);
if(l<x) build(ls[x],l,x-,nxt(type));
if(x<r) build(rs[x],x+,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[]<l || t[x].lb[]>r || t[x].rb[]<u || t[x].lb[]>d)
return ;
if(t[x].lb[]>=l && t[x].rb[]<=r && t[x].lb[]>=u && t[x].rb[]<=d)
return t[x].sum;
ll res=;
if(t[x].p[]>=l && t[x].p[]<=r && t[x].p[]>=u && t[x].p[]<=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=;i<=n;i++)
{
scanf("%d",&a[i]);
tree.t[++sz]=Node(i,a[i],a[i]);
}
for(int i=;i<=q;i++)
{
scanf("%d%d%d",&op[i],&L[i],&R[i]);
if(op[i]==)
tree.t[++sz]=Node(L[i],R[i],);
} tree.build(root,,sz,); for(int i=;i<=q;i++)
if(op[i]==)
{
tree.cur=Node(L[i],a[L[i]]);
tree.insert(root,-a[L[i]],);
tree.cur=Node(L[i],R[i]);
tree.insert(root,R[i],);
a[L[i]]=R[i];
}
else
{
ll x=,res=;
while()
{
res=tree.query(root,L[i],R[i],,min(x+,(ll)N));
if(res==x)
break;
x=res;
}
printf("%lld\n",x+);
}
return ;
}

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=;
int rev=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
if(ch=='-')
rev=-,ch=getchar();
while(isdigit(ch))
x=x*+ch-'',ch=getchar();
x*=rev;
} inline void out(long long x)
{
if(x==)
{
putchar('');
return;
}
int len=;
static char buff[];
while(x)
buff[++len]=x%+'',x/=;
while(len)
putchar(buff[len--]);
} typedef long long ll;
const int N=;
const int M=;
const int DIM=; inline int nxt(int x)
{
if(++x==DIM)
x=;
return x;
} int now; struct Node
{
int p[DIM];
int lb[DIM],rb[DIM];
ll val,maxv; Node(int x=,int y=,ll z=)
{
val=maxv=z;
p[]=x,p[]=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=;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]=;
t[x].val=cur.val;
t[x].maxv=cur.maxv;
for(int i=;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=;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=;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)>>;
now=type;
nth_element(t+l,t+x,t+r+); cur=t[x];
newnode(x); if(l<x)
build(ls[x],l,x-,nxt(type));
if(x<r)
build(rs[x],x+,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[]<cur.lb[] || t[x].lb[]>cur.rb[])
return;
if(t[x].rb[]<cur.lb[] || t[x].lb[]>cur.rb[])
return;
if(t[x].lb[]>=cur.lb[] && t[x].rb[]<=cur.rb[] &&
t[x].lb[]>=cur.lb[] && t[x].rb[]<=cur.rb[])
{
ans=max(ans,t[x].maxv);
return;
} if(t[x].p[]>=cur.lb[] && t[x].p[]<=cur.rb[] &&
t[x].p[]>=cur.lb[] && t[x].p[]<=cur.rb[])
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,,n*n,); for(int i=;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-][y2]-=w;
a[x2][y1-]-=w;
a[x1-][y1-]+=w;
} for(int i=*n;i>=;i--)
{
for(int j=min(n,i-);j>=max(,i-n);j--)
{
int y=j,x=i-j;
a[x][y]+=a[x+][y]+a[x][y+]-a[x+][y+];
tree.t[(x-)*n+y]=Node(x,y,a[x][y]);
}
} tree.build(root,,n*n,); for(int i=;i<=m2;i++)
{
int x1,y1,x2,y2;
read(x1),read(y1),read(x2),read(y2); tree.cur.lb[]=x1,tree.cur.rb[]=x2;
tree.cur.lb[]=y1,tree.cur.rb[]=y2; ll ans=;
tree.query(root,ans);
out(ans),putchar('\n');
}
return ;
}

(完)

K-D树的更多相关文章

  1. 【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题

    达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360 说一下我对这个模板的理解: 看到这个方法很容易不知所措,因为动态K值需要套树状 ...

  2. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  3. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 首先还是吐槽时间,我在zoj交无限tle啊!!!!!!!!我一直以为是程序错了啊啊啊啊啊啊. ...

  4. 【BZOJ】3196: Tyvj 1730 二逼平衡树(区间第k小+树套树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3196 Treap+树状数组 1WA1A,好伤心,本来是可以直接1A的,这次开始我并没有看题解,就写出 ...

  5. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间 ...

  6. Dynamic Rankings(动态第k大+树套树)

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题目: 思路: 树套树板子题. 代码实现如下: #inclu ...

  7. 静态区间第k大 树套树解法

    然而过不去你谷的模板 思路: 值域线段树\([l,r]\)代表一棵值域在\([l,r]\)范围内的点构成的一颗平衡树 平衡树的\(BST\)权值为点在序列中的位置 查询区间第\(k\)大值时 左区间在 ...

  8. 狂K 线段树

    想写好树剖~~线段树very important HDU 1166 敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536 ...

  9. HDU 5412 CRB and Queries(区间第K大 树套树 按值建树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5412 Problem Description There are N boys in CodeLan ...

  10. 吉首大学2019年程序设计竞赛(重现赛)-K(线段树)

    题目链接:https://ac.nowcoder.com/acm/contest/992/K 题意:给一个大小为1e5的数组,由0 1组成,有两种操作,包括区间修改,将一段区间内的0换成1,1换成0; ...

随机推荐

  1. es6 装饰器decorator的使用 +webpack4.0配置

    decorator 装饰器 许多面向对象都有decorator(装饰器)函数,比如python中也可以用decorator函数来强化代码,decorator相当于一个高阶函数,接收一个函数,返回一个被 ...

  2. 关于React的脚手架

    Rewire你的应用 https://ant.design/docs/react/use-with-create-react-app-cn create-react-app (官方脚手架 简称cra) ...

  3. 采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用

    题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...

  4. 【leetcode算法-简单】28. 实现strStr

    [题目描述] 实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如 ...

  5. google搜索设置,在新的窗口打开

  6. TypeScript 迭代器(iterator)和生成器(generator)

    ⒈迭代器(iterator) 1.可迭代性 当一个对象实现了Symbol.iterator属性时,我们认为它是可迭代的. 一些内置的类型如 Array,Map,Set,String,Int32Arra ...

  7. java源码 -- LinkedHashSet

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

  8. GBK字符集

    GBK字库 编辑 同义词 GBK一般指GBK字库 GBK全称<汉字内码扩展规范>(GBK即“国标”.“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Sp ...

  9. python将url转变成二维码图片

    将url数据转变成二维码数据,再将二维码图片转成base64格式返回 import qrcode import io def url_image(self,url): img = qrcode.mak ...

  10. SAS学习笔记18 length、lengthn、lengthc函数