zoukankan      html  css  js  c++  java
  • [ZJOI2013]K大数查询

    VII.[ZJOI2013]K大数查询

    这题常卡的我快哭了QaQ

    首先,我们仍然考虑树套树。

    1. 下标树套权值树(即我们前几题的一贯做法)

    我们发现,要在区间树上打上区间添加数的tag,并且用tag树的并集进行二分。

    因此最终的结果就是,大区间被分割成\(\log n\)个小区间,但是每个小区间的\(\log n\)个父亲区间的tag树都是必须选的。因此总共有\(\log^2n\)tag树在一起二分,因此总复杂度就是\(\log^3n\)的。并且写起来还贼恶心。介于这题贼卡长,我不认为这种方法有通过的可能性。

    1. 权值树套下标树

    现在,我们就是在权值树的某个叶节点上的下标树内,打上一个区间加的tag。当然咯,这叶节点的所有父亲的下标树,也是要打tag的。

    最终的结果就是,修改就是在\(\log n\)个下标树内打区间加tag,复杂度\(\log^2n\)

    然后询问。就直接在权值树上二分,同时在下标树上查询区间和,复杂度\(\log^2n\)

    被卡长的代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m,Inc,root[200100],dis[200100],tp;
    struct Inner{
    	int lson,rson,tag;
    	ll sum;
    }inn[20010000];
    inline void pushdown(const register int &x,const register int &l,const register int &r){
    	register int mid=(l+r)>>1,&val=inn[x].tag;
    	if(!inn[x].lson)inn[x].lson=++Inc;
    	if(!inn[x].rson)inn[x].rson=++Inc;
    	inn[inn[x].lson].sum+=1ll*val*(mid-l+1),inn[inn[x].lson].tag+=val;
    	inn[inn[x].rson].sum+=1ll*val*(r-mid),inn[inn[x].rson].tag+=val;
    	val=0;
    }
    inline void Inner_Add(register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
    	if(!x)x=++Inc;
    	if(L<=l&&r<=R){inn[x].sum+=r-l+1,inn[x].tag++;return;}
    	if(inn[x].tag)pushdown(x,l,r);
    	register int mid=(l+r)>>1;
    	if(mid>=L)Inner_Add(inn[x].lson,l,mid,L,R);
    	if(mid<R)Inner_Add(inn[x].rson,mid+1,r,L,R);
    	inn[x].sum=inn[inn[x].lson].sum+inn[inn[x].rson].sum;
    }
    inline ll Inner_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
    	if(L<=l&&r<=R)return inn[x].sum;
    	if(inn[x].tag)pushdown(x,l,r);
    	register int mid=(l+r)>>1;
    	ll res=0;
    	if(mid>=L&&inn[x].lson)res+=Inner_Ask(inn[x].lson,l,mid,L,R);
    	if(mid<R&&inn[x].rson)res+=Inner_Ask(inn[x].rson,mid+1,r,L,R);
    	return res;
    }
    inline void Outer_Add(const register int &x,const register int &l,const register int &r,const register int &P,const register int &L,const register int &R){
    	Inner_Add(root[x],1,n,L,R);
    	if(l==r)return;
    	register int mid=(l+r)>>1;
    	if(mid>=P)Outer_Add(x<<1,l,mid,P,L,R);
    	else Outer_Add(x<<1|1,mid+1,r,P,L,R);
    }
    inline int Outer_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register ll &k){
    	if(l==r)return l;
    	register ll rsum=Inner_Ask(root[x<<1|1],1,n,L,R);
    	register int mid=(l+r)>>1;
    	if(rsum>=k)return Outer_Ask(x<<1|1,mid+1,r,L,R,k);
    	else return Outer_Ask(x<<1,l,mid,L,R,k-rsum);
    }
    struct Query{
    	int tp,l,r;
    	ll k;
    }q[50100];
    inline void read(register int &x){
    	register char c=getchar();
    	register int fl=1;
    	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	x*=fl;
    }
    inline void read(register ll &x){
    	register char c=getchar();
    	register int fl=1;
    	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	x*=fl;
    }
    inline void print(register int x){
    	if(x<0)putchar('-'),print(-x);
    	else if(x<=9)putchar('0'+x);
    	else print(x/10),putchar('0'+x%10);
    }
    int main(){
    	read(n),read(m);
    	for(register int i=1;i<=m;i++){
    		read(q[i].tp),read(q[i].l),read(q[i].r),read(q[i].k);
    		if(q[i].tp==1)dis[++tp]=q[i].k;
    	}
    	sort(dis+1,dis+tp+1),tp=unique(dis+1,dis+tp+1)-dis-1;
    	for(register int i=1;i<=m;i++){
    		if(q[i].tp==1)Outer_Add(1,1,tp,lower_bound(dis+1,dis+tp+1,q[i].k)-dis,q[i].l,q[i].r);
    		else print(dis[Outer_Ask(1,1,tp,q[i].l,q[i].r,q[i].k)]),putchar('\n');
    	}
    	return 0;
    }
    

    能用的优化就只有在下标树上的标记永久化了。

    因此现学了这个东西,敲出来常数果然快了很多,勉强卡过了:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m,Inc,root[200100],dis[200100],tp;
    struct Inner{
    	int lson,rson,tag;
    	ll sum;
    }inn[20010000];
    inline void Inner_Add(register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
    	if(!x)x=++Inc;
    	inn[x].sum+=max(min(R,r)-max(L,l)+1,0);
    	if(L<=l&&r<=R){inn[x].tag++;return;}
    	register int mid=(l+r)>>1;
    	if(mid>=L)Inner_Add(inn[x].lson,l,mid,L,R);
    	if(mid<R)Inner_Add(inn[x].rson,mid+1,r,L,R);
    }
    inline ll Inner_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register int add=0){
    	if(!x)return 1ll*add*max(min(R,r)-max(L,l)+1,0);
    	if(L<=l&&r<=R)return 1ll*add*(r-l+1)+inn[x].sum;
    	register int mid=(l+r)>>1;
    	register ll res=0;
    	if(mid>=L)res+=Inner_Ask(inn[x].lson,l,mid,L,R,add+inn[x].tag);
    	if(mid<R)res+=Inner_Ask(inn[x].rson,mid+1,r,L,R,add+inn[x].tag);
    	return res;
    }
    inline void Outer_Add(const register int &x,const register int &l,const register int &r,const register int &P,const register int &L,const register int &R){
    	Inner_Add(root[x],1,n,L,R);
    	if(l==r)return;
    	register int mid=(l+r)>>1;
    	if(mid>=P)Outer_Add(x<<1,l,mid,P,L,R);
    	else Outer_Add(x<<1|1,mid+1,r,P,L,R);
    }
    inline int Outer_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register ll &k){
    	if(l==r)return l;
    	register ll rsum=Inner_Ask(root[x<<1|1],1,n,L,R);
    	register int mid=(l+r)>>1;
    	if(rsum>=k)return Outer_Ask(x<<1|1,mid+1,r,L,R,k);
    	else return Outer_Ask(x<<1,l,mid,L,R,k-rsum);
    }
    struct Query{
    	int tp,l,r;
    	ll k;
    }q[50100];
    inline void read(register int &x){
    	register char c=getchar();
    	register int fl=1;
    	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	x*=fl;
    }
    inline void read(register ll &x){
    	register char c=getchar();
    	register int fl=1;
    	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	x*=fl;
    }
    inline void print(register int x){
    	if(x<0)putchar('-'),print(-x);
    	else if(x<=9)putchar('0'+x);
    	else print(x/10),putchar('0'+x%10);
    }
    int main(){
    	read(n),read(m);
    	for(register int i=1;i<=m;i++){
    		read(q[i].tp),read(q[i].l),read(q[i].r),read(q[i].k);
    		if(q[i].tp==1)dis[++tp]=q[i].k;
    	}
    	sort(dis+1,dis+tp+1),tp=unique(dis+1,dis+tp+1)-dis-1;
    	for(register int i=1;i<=m;i++){
    		if(q[i].tp==1)Outer_Add(1,1,tp,lower_bound(dis+1,dis+tp+1,q[i].k)-dis,q[i].l,q[i].r);
    		else print(dis[Outer_Ask(1,1,tp,q[i].l,q[i].r,q[i].k)]),putchar('\n');
    	}
    	return 0;
    }
    

  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611124.html
Copyright © 2011-2022 走看看