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;
    }
    

  • 相关阅读:
    关于Dijkstra三种堆速度的研究
    [BZOJ1041][HAOI2008]圆上的整点[数论]
    [BZOJ2482][Spoj1557] Can you answer these queries II[线段树]
    [CF600E]Lomsat gelral[dsu on tree/树上启发式合并]
    [BZOJ3495]PA2010 Riddle[2-SAT]
    [9.26模拟] 伪造
    [bzoj4722] 由乃
    [bzoj2004] 公交线路
    [51nod1314] 定位系统
    [51nod1143] 路径和树
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611124.html
Copyright © 2011-2022 走看看