• 带插入区间K小值


    这题真毒,BZOJ过了,Luogu没过(请求增长时限QwQ)

    题意(三种操作):

    • 插入一个数到数列中
    • 修改数列中一个数的值
    • 询问区间第(k)

    强制在线。

    然后可怜的我只会 (O(n log^3 n)) 的做法QAQ……
    这道题可以树套树,由于需要动态插点,所以外层树平衡树;由于需要询问区间(k)小值,所以内层树可以是权值线段树(不嫌烦可以写平衡树),维护外层树所在子树的权值信息,显然如果外层树需要旋转操作,维护内层树将相当麻烦,所以我建议外层树写替罪羊树
    对于插入和修改操作,可以根据二叉搜索树的做法进行,同时子树不平衡时暴力重构。
    对于查询操作,用线段树上查询区间的方法用vector存储需要访问的区间,显然最多有(log n)个区间,再二分答案计算(类似主席树的查询操作)。
    目前时间的瓶颈在于重构部分暴力点权插入线段树需要(O(n log^3 n)),使得Luogu上(TLE),BZOJ上(AC)
    然后是代码((TLE)):

    #include<bits/stdc++.h>
    #define ratio 4
    using namespace std;
    inline int read() {
    	register int tmp=0;register char c=getchar(); while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar(); return tmp;
    }
    inline void print(int x) { if(x>9)	print(x/10); putchar(x%10+'0'); }
    
    const int N=70010;
    int n,m,a[N],ans;
    vector <int> q,ttt;
    int root;
    int Tot=0;
    struct ST {
    	int l,r,s;
    	ST(int L,int R,int S):l(L),r(R),s(S) {}
    	ST() {}
    };ST tr[20000010]; int Sta[20000010],Top=0;
    int tot=0;
    struct P {
    	int l,r,val,rt,sz;
    	P(int L,int R,int V,int Rt,int S):l(L),r(R),val(V),rt(Rt),sz(S) {}
    	P() {}
    };P t[N];
    int sta[N],top=0;
    
    inline int Min(const int x,const int y) { return x<y?	x:y; }
    inline int Max(const int x,const int y) { return x>y?	x:y; }
    inline int st_node() {
    	if(!Top) return ++Tot; --Top; return Sta[Top+1];
    }
    void clean(int &u) {
    	if(tr[u].l)	clean(tr[u].l); if(tr[u].r)	clean(tr[u].r);
    	Sta[++Top]=u,tr[u]=ST(0,0,0),u=0;
    }
    void st_insert(int &u,int l,int r,int x,int w) {
    	if(!u)	u=st_node(); tr[u].s+=w;
    	if(l>=r) { if(!tr[u].s)	clean(u); return ; }
    	int mid=(l+r)>>1;
    	x<=mid?	st_insert(tr[u].l,l,mid,x,w):
    			st_insert(tr[u].r,mid+1,r,x,w);
    	if(!tr[u].s)	clean(u);
    }
    void debug(int u,int Tab) {
    	if(t[u].l)	debug(t[u].l,Tab+1);
    	for(int i=1;i<Tab;i++)	printf("     |");
    	printf(" %d
    ",t[u].val);
    	if(t[u].r)	debug(t[u].r,Tab+1);
    }
    inline bool Bad(int u) {
    	return (double)t[t[u].l].sz>ratio*(double)t[t[u].r].sz||
    	       (double)t[t[u].r].sz>ratio*(double)t[t[u].l].sz;
    }
    inline int sgt_node(int l,int r,int v,int sz) {
    	t[sta[top]]=P(l,r,v,0,sz),--top; return sta[top+1];
    }
    void sgt_init(int &u,int l,int r) {
    	int mid=(l+r)>>1; u=sgt_node(0,0,a[mid],r-l+1);
    	for(int i=l;i<=r;i++)	st_insert(t[u].rt,0,70000,a[i],1);
    	if(l<mid)	sgt_init(t[u].l,l,mid-1);
    	if(mid<r)	sgt_init(t[u].r,mid+1,r);
    }
    void ask(int u,int l,int r,int L,int R) {
    	if(L>R||l>r)	return ;
    	if(l==L&&r==R) { q.push_back(u);return ; }
    	int mid=t[t[u].l].sz+l;
    	if(L<=mid&&mid<=R)	ttt.push_back(t[u].val);
    	if(R<mid)	ask(t[u].l,l,mid-1,L,R);
    	else if(L>mid)	ask(t[u].r,mid+1,r,L,R);
    	else	ask(t[u].l,l,mid-1,L,mid-1),ask(t[u].r,mid+1,r,mid+1,R);
    }
    int solve(int l,int r,int k) {
    	ask(root,1,t[root].sz,l,r); int L=0,R=70000,mid,sum;
    	for(int i=0;i<q.size();i++)	q[i]=t[q[i]].rt;
    //	printf("ASK : ");
    //	for(int i=0;i<q.size();i++)	printf(" %d",tr[q[i]].s);printf("
    ");
    //	for(int i=0;i<ttt.size();i++)	printf(" 1",ttt[i]);printf("
    ");
    	while(L<R) {
    		mid=(L+R)>>1,sum=0;
    		for(int i=0;i<q.size();i++)	sum+=tr[tr[q[i]].l].s;
    		for(int i=0;i<ttt.size();i++)	if(ttt[i]<=mid)	++sum;
    //		printf("MWHAKIOI : %d %d
    ",mid,sum);
    		if(sum>=k) {
    			R=mid; for(int i=0;i<q.size();i++)	q[i]=tr[q[i]].l;
    		}
    		else {
    			k-=sum,L=mid+1;
    			for(int i=0;i<q.size();i++)	q[i]=tr[q[i]].r;
    			for(int i=0;i<ttt.size();i++)
    				if(ttt[i]<=mid)	ttt[i]=70010;
    		}
    	}
    	q.clear(),ttt.clear(); return R;
    }
    int sgt_find(int u,int k) {
    	if(t[t[u].l].sz+1==k)	return t[u].val;
    	if(k<=t[t[u].l].sz)	return sgt_find(t[u].l,k);
    	return sgt_find(t[u].r,k-t[t[u].l].sz-1);
    }
    void sgt_mdy(int u,int k,int Old,int New) {
    	st_insert(t[u].rt,0,70000,Old,-1),
    	st_insert(t[u].rt,0,70000,New,1);
    	if(t[t[u].l].sz+1==k) { t[u].val=New;return ; }
    	k<=t[t[u].l].sz?	sgt_mdy(t[u].l,k,Old,New):
    	sgt_mdy(t[u].r,k-t[t[u].l].sz-1,Old,New);
    }
    void dfs(int &u) {
    	if(t[u].l)	dfs(t[u].l);
    	a[++n]=t[u].val,clean(t[u].rt),sta[++top]=u;
    	if(t[u].r)	dfs(t[u].r);
    	u=0;
    }
    void rebuild(int &u) { n=0,dfs(u),sgt_init(u,1,n); }
    void sgt_insert(int &u,int x,int w) {
    	if(!u) {
    		u=sgt_node(0,0,w,1),st_insert(t[u].rt,0,70000,w,1);
    		return ;
    	}
    	st_insert(t[u].rt,0,70000,w,1),++t[u].sz;
    	if(x<=t[t[u].l].sz)	sgt_insert(t[u].l,x,w);
    	else	sgt_insert(t[u].r,x-t[t[u].l].sz-1,w);
    	if(!Bad(u)) {
    		if(Bad(t[u].l))	rebuild(t[u].l);
    		if(Bad(t[u].r))	rebuild(t[u].r);
    	}
    }
    int main() {
    	n=read();
    	for(register int i=1;i<=n;++i)	a[i]=read(); m=read();
    	for(register int i=1;i<N;++i)	sta[++top]=i;
    	sgt_init(root,1,n);
    //	printf("Array : 
    "),debug(root,1),printf("
    ");
    	for(;m;--m) {
    		register char opt=getchar();
    		while(opt<'A'||opt>'Z')	opt=getchar();
    		if(opt=='Q') {
    			register int l=read()^ans,r=read()^ans,k=read()^ans;
    			ans=solve(l,r,k),print(ans),putchar(10);
    		}
    		else if(opt=='M') {
    			register int x=read()^ans,y=read()^ans,z;
    			z=sgt_find(root,x),sgt_mdy(root,x,z,y);
    		}
    		else {
    			register int x=read()^ans,y=read()^ans;
    			sgt_insert(root,x-1,y); if(Bad(root))	rebuild(root);
    		}
    //		printf("Array : 
    "),debug(root,1),printf("
    ");
    	}
    	return 0;
    }
    

    目前想到的解决方式:

    • 线段树合并
    • leafy tree 实现重量平衡树(线段树合并)

    (然而这么做好像有问题)

    被卡的代码:

    #include<bits/stdc++.h>
    #define ratio 3
    using namespace std;
    inline int read() {
    	register int tmp=0;register char c=getchar();
    	while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar();
    	return tmp;
    }
    inline void print(int x) { if(x>9)	print(x/10); putchar(x%10+'0'); }
    
    const int N=70010;
    int n,m,a[N],ans;
    vector <int> q,ttt;
    int root;
    int Tot=0;
    struct ST {
    	int l,r,s;
    	ST(int L,int R,int S):l(L),r(R),s(S) {}
    	ST() {}
    };ST tr[20000010]; int Sta[20000010],Top=0;
    int tot=0;
    struct P {
    	int l,r,val,rt,sz;
    	P(int L,int R,int V,int Rt,int S):l(L),r(R),val(V),rt(Rt),sz(S) {}
    	P() {}
    };P t[N];
    int sta[N],top=0;
    
    inline int Min(const int &x,const int &y) { return x<y?	x:y; }
    inline int Max(const int &x,const int &y) { return x>y?	x:y; }
    inline int st_node() {
    	if(!Top) return ++Tot; --Top; return Sta[Top+1];
    }
    void clean(int &u) {
    	if(tr[u].l)	clean(tr[u].l); if(tr[u].r)	clean(tr[u].r);
    	Sta[++Top]=u,tr[u]=ST(0,0,0),u=0;
    }
    void st_insert(int &u,int l,int r,int x,int w) {
    	if(!u)	u=st_node(); tr[u].s+=w;
    	if(l>=r) { if(!tr[u].s)	clean(u); return ; }
    	int mid=(l+r)>>1;
    	x<=mid?	st_insert(tr[u].l,l,mid,x,w):
    			st_insert(tr[u].r,mid+1,r,x,w);
    	if(!tr[u].s)	clean(u);
    }
    void debug(int u,int Tab) {
    	if(t[u].l)	debug(t[u].l,Tab+1);
    	for(int i=1;i<Tab;i++)	printf("     |");
    	printf(" %d
    ",t[u].val);
    	if(t[u].r)	debug(t[u].r,Tab+1);
    }
    inline bool Bad(int u) {
    	return (double)t[t[u].l].sz>ratio*(double)t[t[u].r].sz||
    	       (double)t[t[u].r].sz>ratio*(double)t[t[u].l].sz;
    }
    inline int sgt_node(int l,int r,int v,int sz) {
    	t[sta[top]]=P(l,r,v,0,sz),--top; return sta[top+1];
    }
    void Merge(int &u,int l,int r,int L,int R) {
    	if(!l&&!r)	return ;
    	u=st_node(),tr[u].s=tr[l].s+tr[r].s;
    	if(l==r)	return ;
    	int mid=(L+R)>>1;
    	Merge(tr[u].l,tr[l].l,tr[r].l,L,mid),
    	Merge(tr[u].r,tr[l].r,tr[r].r,mid+1,r);
    }
    void sgt_init(int &u,int l,int r) {
    	int mid=(l+r)>>1; u=sgt_node(0,0,a[mid],r-l+1);
    	if(l<mid)	sgt_init(t[u].l,l,mid-1);
    	if(mid<r)	sgt_init(t[u].r,mid+1,r);
    	Merge(t[u].rt,t[t[u].l].rt,t[t[u].r].rt,0,70000);
    	st_insert(t[u].rt,0,70000,a[mid],1);
    }
    void ask(int u,int l,int r,int L,int R) {
    	if(L>R||l>r)	return ;
    	if(l==L&&r==R) { q.push_back(u);return ; }
    	int mid=t[t[u].l].sz+l;
    	if(L<=mid&&mid<=R)	ttt.push_back(t[u].val);
    	if(R<mid)	ask(t[u].l,l,mid-1,L,R);
    	else if(L>mid)	ask(t[u].r,mid+1,r,L,R);
    	else	ask(t[u].l,l,mid-1,L,mid-1),ask(t[u].r,mid+1,r,mid+1,R);
    }
    int solve(int l,int r,int k) {
    	ask(root,1,t[root].sz,l,r); int L=0,R=70000,mid,sum;
    	for(int i=0;i<q.size();i++)	q[i]=t[q[i]].rt;
    //	printf("ASK : ");
    //	for(int i=0;i<q.size();i++)	printf(" %d",tr[q[i]].s);printf("
    ");
    //	for(int i=0;i<ttt.size();i++)	printf(" 1",ttt[i]);printf("
    ");
    	while(L<R) {
    		mid=(L+R)>>1,sum=0;
    		for(int i=0;i<q.size();i++)	sum+=tr[tr[q[i]].l].s;
    		for(int i=0;i<ttt.size();i++)	if(ttt[i]<=mid)	++sum;
    //		printf("MWHAKIOI : %d %d
    ",mid,sum);
    		if(sum>=k) {
    			R=mid; for(int i=0;i<q.size();i++)	q[i]=tr[q[i]].l;
    		}
    		else {
    			k-=sum,L=mid+1;
    			for(int i=0;i<q.size();i++)	q[i]=tr[q[i]].r;
    			for(int i=0;i<ttt.size();i++)
    				if(ttt[i]<=mid)	ttt[i]=70010;
    		}
    	}
    	q.clear(),ttt.clear(); return R;
    }
    int sgt_find(int u,int k) {
    	if(t[t[u].l].sz+1==k)	return t[u].val;
    	if(k<=t[t[u].l].sz)	return sgt_find(t[u].l,k);
    	return sgt_find(t[u].r,k-t[t[u].l].sz-1);
    }
    void sgt_mdy(int u,int k,int Old,int New) {
    	st_insert(t[u].rt,0,70000,Old,-1),
    	st_insert(t[u].rt,0,70000,New,1);
    	if(t[t[u].l].sz+1==k) { t[u].val=New;return ; }
    	k<=t[t[u].l].sz?	sgt_mdy(t[u].l,k,Old,New):
    	sgt_mdy(t[u].r,k-t[t[u].l].sz-1,Old,New);
    }
    void dfs(int &u) {
    	if(t[u].l)	dfs(t[u].l);
    	a[++n]=t[u].val,clean(t[u].rt),sta[++top]=u;
    	if(t[u].r)	dfs(t[u].r);
    	u=0;
    }
    void rebuild(int &u) { n=0,dfs(u),sgt_init(u,1,n); }
    void sgt_insert(int &u,int x,int w) {
    	if(!u) {
    		u=sgt_node(0,0,w,1),st_insert(t[u].rt,0,70000,w,1);
    		return ;
    	}
    	st_insert(t[u].rt,0,70000,w,1),++t[u].sz;
    	if(x<=t[t[u].l].sz)	sgt_insert(t[u].l,x,w);
    	else	sgt_insert(t[u].r,x-t[t[u].l].sz-1,w);
    	if(!Bad(u)) {
    		if(Bad(t[u].l))	rebuild(t[u].l);
    		if(Bad(t[u].r))	rebuild(t[u].r);
    	}
    }
    int main() {
    	n=read();
    	for(register int i=1;i<=n;++i)	a[i]=read(); m=read();
    	for(register int i=1;i<N;++i)	sta[++top]=i;
    	sgt_init(root,1,n);
    //	printf("Array : 
    "),debug(root,1),printf("
    ");
    	for(;m;--m) {
    		register char opt=getchar();
    		while(opt<'A'||opt>'Z')	opt=getchar();
    		if(opt=='Q') {
    			register int l=read()^ans,r=read()^ans,k=read()^ans;
    			ans=solve(l,r,k),print(ans),putchar(10);
    		}
    		else if(opt=='M') {
    			register int x=read()^ans,y=read()^ans,z;
    			z=sgt_find(root,x),sgt_mdy(root,x,z,y);
    		}
    		else {
    			register int x=read()^ans,y=read()^ans;
    			sgt_insert(root,x-1,y); if(Bad(root))	rebuild(root);
    		}
    //		printf("Array : 
    "),debug(root,1),printf("
    ");
    	}
    	return 0;
    }
    

    然后仅剩下的思路是块状链表,若能做到(O(n sqrt {n})) 同样理论可过。
    我尝试去敲块状链表,由于常数优秀,跑得比(O(n log^2 n))还快,Luogu上过了60%的数据。听说某位大神用块状链表卡进去了,吾辈表示无能为力。
    写题没有必要做对,写题的目的是锻炼思维和解题方式,留下思考的痕迹,这样写题才有意义。
    最后我在这里留下块状链表写法的代码。

    #include<bits/stdc++.h>
    #define ONLINE_JUDGE
    #define re register
    using namespace std;
    const int N=70000,BLOSIZE=1100,MXBLO=2*N/BLOSIZE;
    int n,m;
    
    struct P {
    	int a[3*BLOSIZE+100],b[3*BLOSIZE+100],sz,to;
    	void reset() {
    		for(re int i=1;i<=sz;++i)	b[i]=a[i];
    		sort(b+1,b+sz+1);
    	}
    };P t[MXBLO+100];
    int tot=0;
    
    inline int read() {
    	re int x=0;re char c=getchar();
    	while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    void print(int x) { if(x>9)	print(x/10); putchar(x%10+'0'); }
    inline void insert(int x,int w) {
    	re int u,tt;
    	for(u=0;u!=-1&&x>t[u].sz;u=t[u].to)	x-=t[u].sz;
    	for(re int i=t[u].sz;i>=x;--i)	t[u].a[i+1]=t[u].a[i];
    	t[u].a[x]=w,++t[u].sz;
    	if(t[u].sz>=2*BLOSIZE) {
    		int nu=++tot; t[nu].to=t[u].to,t[u].to=nu;
    		t[nu].sz=t[u].sz-BLOSIZE;
    		for(re int i=BLOSIZE+1;i<=t[u].sz;++i)
    			t[nu].a[i-BLOSIZE]=t[nu].b[i-BLOSIZE]=t[u].a[i];
    		for(re int i=1;i<=BLOSIZE;++i) t[u].b[i]=t[u].a[i];
    		t[u].sz=BLOSIZE;
    		sort(t[nu].b+1,t[nu].b+t[nu].sz+1),
    		sort(t[u].b+1,t[u].b+t[u].sz+1); return ;
    	}
    	tt=t[u].sz-1;
    	for(;tt;--tt) {
    		if(t[u].b[tt]>w)	t[u].b[tt+1]=t[u].b[tt];
    		else	break;
    	}
    	t[u].b[tt+1]=w;
    }
    void modify(int x,int w) {
    	re int u,tt;
    	for(u=0;u!=-1&&x>t[u].sz;u=t[u].to)	x-=t[u].sz;
    	for(re int i=1;i<=t[u].sz;++i)
    		if(t[u].b[i]==t[u].a[x]) {
    			for(re int j=i;j<t[u].sz;++j)
    				t[u].b[j]=t[u].b[j+1];
    			t[u].b[t[u].sz--]=0;break;
    		}
    	t[u].a[x]=w,tt=t[u].sz;
    	for(;tt;--tt) {
    		if(t[u].b[tt]>w) t[u].b[tt+1]=t[u].b[tt];
    		else	break;
    	}
    	t[u].b[tt+1]=w,++t[u].sz;
    }
    int query(int x,int y,int w) {
    	re int u,v,sum=0,l,r,mid,tt;
    	for(u=0;u!=-1&&x>t[u].sz;u=t[u].to)	x-=t[u].sz;
    	for(v=0;v!=-1&&y>t[v].sz;v=t[v].to)	y-=t[v].sz;
    	if(u==v) {
    		for(int i=x;i<=y;i++) if(t[u].a[i]<w) ++sum;
    		return sum;
    	}
    	for(re int i=x;i<=t[u].sz;++i) if(t[u].a[i]<w) ++sum;
    	for(re int i=1;i<=y;++i) if(t[v].a[i]<w) ++sum;
    	for(re int i=t[u].to;i!=v;i=t[i].to) {
    		l=1,r=t[i].sz,tt=0;
    		while(l<=r) {
    			mid=(l+r)>>1;
    			t[i].b[mid]<w?	(tt=mid,l=mid+1):r=mid-1;
    		}
    		sum+=tt;
    	}
    	return sum;
    }
    void init() {
    	t[0].to=-1,t[0].sz=0,n=read(); int cnt=BLOSIZE,Old=0;
    	for(re int i=1;i<=n;++i) {
    		if(cnt==BLOSIZE) {
    			int u=++tot;
    			t[u].to=t[Old].to,t[Old].to=u,
    			sort(t[Old].b+1,t[Old].b+t[Old].sz+1);
    			Old=u,cnt=0;
    		}
    		t[Old].a[++t[Old].sz]=read(),
    		t[Old].b[t[Old].sz]=t[Old].a[t[Old].sz],
    		++cnt;
    	}
    	if(cnt==BLOSIZE) {
    		int u=++tot;
    		t[u].to=t[Old].to,t[Old].to=u,
    		sort(t[Old].b+1,t[Old].b+t[Old].sz+1);
    		Old=u,cnt=0;
    	}
    	t[Old].a[++t[Old].sz]=70000,
    	t[Old].b[t[Old].sz]=t[Old].a[t[Old].sz],
    	sort(t[Old].b+1,t[Old].b+t[Old].sz+1);
    	m=read();
    }
    void debug() {
    	for(int i=0;i!=-1;i=t[i].to) {
    		printf(" ( [%d]",i);
    		for(int j=1;j<=t[i].sz;++j)
    			printf(" %d",t[i].b[j]);
    		printf(" )");
    	}
    	printf("
    ");
    }
    int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("Dynamic Kth in range.in","r",stdin);
    	freopen("Dynamic Kth in range.out","w",stdout);
    	int cur=clock();
    	#endif
    	char c; int x,y,k,ans=0,l,r,mid; init();
    	for(;m;--m) {
    		c=getchar(); while(c<'A'||c>'Z')	c=getchar();
    		switch(c) {
    			case 'Q':
    				x=read()^ans,y=read()^ans,k=read()^ans;
    				l=0,r=70000;
    				while(l<=r) {
    					mid=(l+r)>>1;
    					query(x,y,mid)<k?
    						(l=mid+1,ans=mid):r=mid-1;
    				}
    				print(ans),putchar(10);break;
    			case 'I':
    				x=read()^ans,y=read()^ans,insert(x,y);break;
    			default:	x=read()^ans,y=read()^ans,modify(x,y);
    		}
    		#ifndef ONLINE_JUDGE
    		ans=0;
    		#endif
    	}
    	#ifndef ONLINE_JUDGE
    	printf(">>> %d ms.",clock()-cur);
    	fclose(stdin),fclose(stdout);
    	#endif
    	return 0;
    }
    
  • 相关阅读:
    C#中添加文本框的上标及文字大小
    综采工作面设备接替计划管理系统
    一位年轻女董事长的27条忠告
    开发人员一定要加入收藏夹的网站
    哈佛图书馆墙上的名训
    加密、解密.NET字符串
    C#文件上传下载
    DotNetNuke3.0.8 简体中文语言包(可直接导入版)发布
    DNN的Core Team
    DotNetNuke3.0.8文件管理器的错误及解决方法
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10170751.html
Copyright © 2020-2023  润新知