kd-tree+替罪羊重构
大概复习了一下kd-tree。
主要就是矩形查询的剪枝。
有时候用替罪羊重构,或者每m次操作重构。
然后矩形k大查询可以线段树套kd-tree : orz claris的常数 : 非递归+只插入右边
比赛的时候感觉比较难写的大数据结构可以大胆用kd-tree水。
根据赛场时间和通过率而定吧
claris的板,我改成了bzoj 4066
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const double A=0.8;
const int N=200010,M=1600010;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,ans,cmp_d,op,X1,Y1,X2,Y2,k;
int tmp[N],deep,need[N],cnt,cur;
int root;
//size : 子树大小 , 用于重构
struct node{int d[2],l,r,Max[2],Min[2],size,a,sum;}t[N];
inline bool cmp(int a,int b){return t[a].d[cmp_d]<t[b].d[cmp_d];}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline void up(int x){
t[x].size=1+t[t[x].l].size+t[t[x].r].size;
t[x].sum = t[x].a + t[t[x].l].sum + t[t[x].r].sum;
if(t[x].l){
umax(t[x].Max[0],t[t[x].l].Max[0]);
umin(t[x].Min[0],t[t[x].l].Min[0]);
umax(t[x].Max[1],t[t[x].l].Max[1]);
umin(t[x].Min[1],t[t[x].l].Min[1]);
}
if(t[x].r){
umax(t[x].Max[0],t[t[x].r].Max[0]);
umin(t[x].Min[0],t[t[x].r].Min[0]);
umax(t[x].Max[1],t[t[x].r].Max[1]);
umin(t[x].Min[1],t[t[x].r].Min[1]);
}
}
int build(int l,int r,int D){
int mid=(l+r)>>1;
cmp_d=D;
nth_element(need+l+1,need+mid+1,need+r+1,cmp);
int x=need[mid];
t[x].Max[0]=t[x].Min[0]=t[x].d[0];
t[x].Max[1]=t[x].Min[1]=t[x].d[1];
if(l!=mid)t[x].l=build(l,mid-1,!D);else t[x].l=0;
if(r!=mid)t[x].r=build(mid+1,r,!D);else t[x].r=0;
up(x);
return x;
}
void dfs(int x){if(x)need[++cnt]=x,dfs(t[x].l),dfs(t[x].r);}
inline void ins(int&root,int now){
if(!root){root=now;return;}
for(int D=deep=0,x=root;;D^=1){ //非递归的插入,直接边插入边update
tmp[++deep]=x;
umax(t[x].Max[0],t[now].Max[0]);
umax(t[x].Max[1],t[now].Max[1]);
umin(t[x].Min[0],t[now].Min[0]);
umin(t[x].Min[1],t[now].Min[1]);
t[x].size++ , t[x].sum += t[now].a;
if(t[now].d[D]>=t[x].d[D]){
if(!t[x].r){t[x].r=now;break;}else x=t[x].r;
}else{
if(!t[x].l){t[x].l=now;break;}else x=t[x].l;
}
}
tmp[++deep]=now;
if(deep<log(t[root].size)/log(1/A))return;
while((double)t[t[now].l].size<A*t[now].size&&(double)t[t[now].r].size<A*t[now].size)now=tmp[--deep]; //重构
if(!now)return;
if(now==root){
cnt=0,dfs(root);
root=build(1,cnt,0);
return;
}
int y=tmp[--deep];
cnt=0,dfs(now);
int k=build(1,cnt,deep&1);
if(t[y].l==now)t[y].l=k;else t[y].r=k;
}
void ask(int x){
if(!x||t[x].Max[0]<X1||t[x].Min[0]>X2||t[x].Max[1]<Y1||t[x].Min[1]>Y2)return;
if(t[x].Min[0]>=X1&&t[x].Max[0]<=X2&&t[x].Min[1]>=Y1&&t[x].Max[1]<=Y2){ans+=t[x].sum;return;} //ans 是全局变量,也可以改成return ans
if(t[x].d[0]>=X1&&t[x].d[0]<=X2&&t[x].d[1]>=Y1&&t[x].d[1]<=Y2)ans += t[x].a;
ask(t[x].l);ask(t[x].r);
}
int lastans;
int main(){
scanf("%d",&n);
while ( 1 ){
int opt,x,y,A;
read(opt);
if ( opt == 3 ) break;
if ( opt == 1 ){
read(x) , read(y) , read(A);
x ^= lastans , y ^= lastans, A ^= lastans;
++cur;
t[cur].Max[0]=t[cur].Min[0]=t[cur].d[0]=x;
t[cur].Max[1]=t[cur].Min[1]=t[cur].d[1]=y;
t[cur].size = 1 , t[cur].sum = t[cur].a = A;
ins(root,cur);
}
else{
read(X1) , read(Y1) , read(X2) , read(Y2);
X1 ^= lastans , Y1 ^= lastans, X2 ^= lastans , Y2 ^= lastans;
ans = 0 , ask(root);
lastans = ans;
printf("%d\n",lastans);
}
}
}
后缀平衡树(替罪羊树)
用于维护相对排名
直接用long long。
维护每个节点的区间,权值即为区间中点,巧妙的保证了权值符合二叉排序树的左小右大
重构时记得更改
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int N = 5e5 + 10;
const int maxn = 100020;
int n,st,rt,cnt,tot,cur[N+5],Void[N+5],m;
const double alpha=0.75;
const ll inf = (1ll << 62);
struct Scapegoat
{
int Son[2],Exist,Size,Fac,ls,rs;
ll L,R,Val;
}node[N+5];
inline void Init()
{
tot=0;
for(register int i=N-1;i;--i) Void[++tot]=i;
}
inline bool balance(int x)
{
return (double)node[x].Fac*alpha>(double)max(node[node[x].Son[0]].Fac,node[node[x].Son[1]].Fac);
}
inline void Build(int x)
{
node[x].Son[0]=node[x].Son[1]=0,node[x].Size=node[x].Fac=1;
}
inline int Insert(int &x,int ls,int rs,ll L,ll R) //L,R是当前的值域区间
{
if(!x)
{
x = Void[tot--];
node[x].ls = ls , node[x].rs = rs , node[x].Val = (L + R) >> 1 , node[x].L = L , node[x].R = R;
node[x].Exist = 1;
Build(x);
return x;
}
if ( node[ls].Val == node[node[x].ls].Val && node[rs].Val == node[node[x].rs].Val ) return x;
++node[x].Size , ++node[x].Fac;
ll mid = (L + R) >> 1;
if(node[ls].Val < node[node[x].ls].Val || (node[ls].Val == node[node[x].ls].Val && node[rs].Val < node[node[x].rs].Val) ) return Insert(node[x].Son[0],ls,rs,L,mid);
return Insert(node[x].Son[1],ls,rs,mid,R);
}
inline void PushUp(int x)
{
node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1,node[x].Fac=node[node[x].Son[0]].Fac+node[node[x].Son[1]].Fac+1;
}
inline void Traversal(int x)
{
if(!x) return;
Traversal(node[x].Son[0]);
if(node[x].Exist) cur[++cnt]=x;
else Void[++tot]=x;
Traversal(node[x].Son[1]);
}
inline void SetUp(int l,int r,int &x,ll L,ll R)
{
int mid=l+r>>1;x=cur[mid]; ll Mid = (L + R) >> 1; //记得更新每个节点的区间
node[x].L = L , node[x].R = R , node[x].Val = Mid;
if(l==r)
{
Build(x);
return;
}
if(l<mid) SetUp(l,mid-1,node[x].Son[0],L,Mid);
else node[x].Son[0]=0;
SetUp(mid+1,r,node[x].Son[1],Mid,R),PushUp(x);
}
inline void ReBuild(int &x)
{
cnt=0,Traversal(x);
if(cnt) SetUp(1,cnt,x,node[x].L,node[x].R);
else x=0;
}
inline void check(int x,ll val)
{
int s=val<=node[x].Val?0:1;
while(node[x].Son[s])
{
if(!balance(node[x].Son[s]))
{
ReBuild(node[x].Son[s]);
return;
}
x=node[x].Son[s],s=val<=node[x].Val?0:1;
}
}
inline int get_rank(int v)
{
int x=rt,rk=1;
while(x)
{
if(node[x].Val>=v) x=node[x].Son[0];
else rk+=node[node[x].Son[0]].Fac+node[x].Exist,x=node[x].Son[1];
}
return rk;
}
inline int get_val(int rk)
{
int x=rt;
while(x)
{
if(node[x].Exist&&node[node[x].Son[0]].Fac+1==rk) return node[x].Val;
else if(node[node[x].Son[0]].Fac>=rk) x=node[x].Son[0];
else rk-=node[x].Exist+node[node[x].Son[0]].Fac,x=node[x].Son[1];
}
}
inline void Delete(int &x,int rk) //后缀平衡树一般不用删除
{
if(node[x].Exist&&!((node[node[x].Son[0]].Fac+1)^rk))
{
node[x].Exist=0,--node[x].Fac;
return;
}
--node[x].Fac;
if(node[node[x].Son[0]].Fac+node[x].Exist>=rk) Delete(node[x].Son[0],rk);
else Delete(node[x].Son[1],rk-node[x].Exist-node[node[x].Son[0]].Fac);
}
inline void del(int v)
{
Delete(rt,get_rank(v));
if((double)node[rt].Size*alpha>(double)node[rt].Fac) ReBuild(rt);
}
namespace SGT{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
int id[N << 2],a[N];
void build(int x,int l,int r){
if ( l == r ){ id[x] = l; return; }
int mid = (l + r) >> 1;
build(ls(x),l,mid) , build(rs(x),mid + 1,r);
id[x] = l;
}
inline int update(int p1,int p2){
if ( !p1 ) return p2;
if ( !p2 ) return p1;
if ( node[a[p1]].Val > node[a[p2]].Val || (node[a[p1]].Val == node[a[p2]].Val && p1 < p2) ) return p1;
return p2;
}
void modify(int x,int l,int r,int p,int num){
if ( l == r ){
a[l] = num;
id[x] = l;
return;
}
int mid = (l + r) >> 1;
if ( p <= mid ) modify(ls(x),l,mid,p,num);
else modify(rs(x),mid + 1,r,p,num);
id[x] = update(id[ls(x)],id[rs(x)]);
}
int query(int x,int l,int r,int L,int R){
if ( L <= l && R >= r ){
return id[x];
}
int mid = (l + r) >> 1;
int res1 = 0 , res2 = 0;
if ( L <= mid ) res1 = query(ls(x),l,mid,L,R);
if ( R > mid ) res2 = query(rs(x),mid + 1,r,L,R);
return update(res1,res2);
}
}
void init(){
Init();
int cur = Insert(rt,0,0,0,inf);
rep(i,1,n) SGT::a[i] = cur;
SGT::build(1,1,n);
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
init();
while ( m-- ){
char ch[10]; int l,r,k;
scanf("%s",ch);
if ( ch[0] == 'C' ){
scanf("%d %d %d",&l,&r,&k);
st = rt;
int cur = Insert(rt,SGT::a[l],SGT::a[r],0,inf);
check(rt,node[cur].Val);
SGT::a[k] = cur;
SGT::modify(1,1,n,k,cur);
// cout<<"check ";
// rep(i,1,n) cout<<SGT::a[i]<<" "<<node[SGT::a[i]].Val<<endl;
// cout<<endl;
}
else{
scanf("%d %d",&l,&r);
printf("%d\n",SGT::query(1,1,n,l,r));
}
}
}