[树套树]K大数查询
Posted CHADLZX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[树套树]K大数查询相关的知识,希望对你有一定的参考价值。
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
为了强制在线,每一次的a,b是加密的,需要异或lastans的后8位进行解密,其中lastans为上次输出的结果,初始为零。
如果解密后a>b则先交换a,b
数据保证解密后a,b不会超过N
如果解密后a,b出现0,则赋值为1。
来历:bzoj上的一道题,经过子祯学长的魔改后,数据范围变得很奇怪...
算法:树套树;
权值线段树套线段树;
套线段树有技巧:一颗线段树可以先只创造一个点,其他需要的节点需要用到的时候再开就可以了;
其他的也没什么可说了,看代码吧:
(不要交到bzoj上,过不了,这是经过魔改的题目)
(不建议借鉴,初次写这种题,code还比较稚嫩)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<set> #include<map> #include<queue> #include<algorithm> #include<iomanip> #include<stack> using namespace std; #define FILE "dealing" #define up(i,j,n) for(int i=(j);i<=(n);i++) #define pii pair<int,int> #define LL long long #define mem(f,g) memset(f,g,sizeof(f)) namespace IO{ char buf[1<<15],*fs,*ft; int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;} int read(){ int ch=gc(),f=0,x=0; while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=gc();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=gc();} return f?-x:x; } int readint(){ int ch=getchar(),f=0,x=0; while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} return f?-x:x; } }using namespace IO; const int maxn=201000,inf=1000000000; int n,m; int ch[maxn],l[maxn],r[maxn],k[maxn],f[maxn]; struct node{ int k,id; bool operator<(const node& b)const{return k<b.k;} }Cnt[maxn]; int L=0; namespace OI{ #define mid ((l+r)>>1) const int maxm=20000000; int root=0,c[maxn][2],id[maxn],cnt=0;//权值线段树 LL sum[maxm],flag[maxm]; int d[maxm][2],len=0;//区间线段树 int x,y,key; void pushdown(int o,int l,int r){ if(flag[o]){ if(l!=r&&!d[o][0])d[o][0]=++len; if(l!=r&&!d[o][1])d[o][1]=++len; sum[d[o][0]]+=flag[o]*(mid-l+1); sum[d[o][1]]+=flag[o]*(r-mid); flag[d[o][0]]+=flag[o]; flag[d[o][1]]+=flag[o]; flag[o]=0; } } void change(int l,int r,int& o){ if(l>y||r<x)return; if(!o)o=++len; if(l>=x&&r<=y){ sum[o]+=r-l+1; flag[o]++; return; } pushdown(o,l,r); change(l,mid,d[o][0]); change(mid+1,r,d[o][1]); sum[o]=sum[d[o][1]]+sum[d[o][0]]; } void insert(int l,int r,int& o){ if(l>key||r<key)return; if(!o)o=++cnt; change(1,n,id[o]); if(l==key&&r==key)return; insert(l,mid,c[o][0]); insert(mid+1,r,c[o][1]); } void init(int l,int r,int k){ x=l,y=r,key=k; insert(1,L,root); } int query2(int l,int r,int o){ if(l>y||r<x||!o)return 0; if(l>=x&&r<=y)return sum[o]; pushdown(o,l,r); return query2(l,mid,d[o][0])+query2(mid+1,r,d[o][1]); } int query1(int l,int r,int o){ if(!o||r<=key)return 0; if(l>key)return query2(1,n,id[o]); return query1(l,mid,c[o][0])+query1(mid+1,r,c[o][1]); } int Query(int l,int r,int val){ x=l,y=r,key=val; return query1(1,L,root)+1; } int Q(int l,int r,int k){ int left=1,right=L,midd,p; while(left+1<right){ midd=(left+right)>>1; if(Query(l,r,midd)>k)left=midd; else right=midd; } if(Query(l,r,left)>k&&Query(l,r,right)<=k)return right; else return left; } }using namespace OI; void print(int *a,int n){up(i,1,n)printf("%d ",a[i]);cout<<endl;} int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); n=read(),m=read(); up(i,1,m){ ch[i]=read(),l[i]=read(),r[i]=read(),k[i]=read(); if(ch[i]==1)Cnt[++L].k=k[i],Cnt[L].id=i; } sort(Cnt+1,Cnt+L+1); up(i,1,L)f[Cnt[i].id]=i; int pre=0,d=(1LL<<8)-1; up(i,1,m){ l[i]^=(pre&d),r[i]^=(pre&d); if(!l[i])l[i]=1;if(!r[i])r[i]=1; if(l[i]>r[i])swap(l[i],r[i]); if(ch[i]==1)init(l[i],r[i],f[i]); if(ch[i]==2)printf("%d\n",pre=Cnt[Q(l[i],r[i],k[i])].k); } return 0; }
以上是关于[树套树]K大数查询的主要内容,如果未能解决你的问题,请参考以下文章