【BZOJ3110】【Zjoi2013】K大数查询
以后写数据结构还是要注意空间问题= =
原题:
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
有点奇怪的区间第k大,用煮席树好像没法做,选择权值线段树套区间线段树
之前一直想不明白树套树怎么搞,主要问题在于修改外面的树的一个区间中的里面的树的一个区间,外面的树区间修改的标记似乎不好控制(因为同一个节点多次修改修改的里面的树的区间不一定一样)
然后这道题因为是权值线段树和区间线段树套,权值线段树是单点修改,所以直接把权值线段树放到外层,然后暴力修改里面的区间线段树即可
(外面的单点修改可以保留修改里面,但是外面如果区间修改就不行了,因为单点nlogn,区间最坏nlogn)
然后空间问题,被迫把两个树分成两个数组写,然后里面push_down的时候调用成外面的
然后debug了7h……
最后发现依旧会MLE,只能把树里面存的left和right放到外面作为参数,mid在每个节点询问或修改的时候现场计算
(其实大部分人都是这么写的,我只是不习惯= =)
如果把left和right作为参数似乎就可以把里外两个树用一个数组了?
以后还是要用把left和right做参数的写法= =
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 long long read(){long long z=0,mark=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mark; 11 } 12 int n,m; int N; 13 struct dcd{int sleft,sright,mid,root;}tree[1700000]; 14 struct ddc{int mid,lchild,rchild,delta; long long svalue;}tree_2[21000000]; 15 //数字个数最坏5e4*5e4会爆int 16 int tree_cnt=0; 17 int new_node(int x){ 18 tree_2[x].lchild=tree_2[x].rchild=tree_2[x].svalue=tree_2[x].delta=0; 19 return x; 20 } 21 void get_SegmentTree(int x,int _left,int _right){ 22 tree[x].sleft=_left,tree[x].sright=_right,tree[x].mid=(_left+_right)>>1; 23 tree[x].root=new_node(++tree_cnt); 24 if(_left!=_right){ 25 get_SegmentTree(x<<1,_left,tree[x].mid); 26 get_SegmentTree(x<<1|1,tree[x].mid+1,_right); 27 } 28 } 29 void push_down(int x,int uleft,int uright){ 30 int umid=(uleft+uright)>>1; 31 if(!tree_2[x].lchild) tree_2[x].lchild=new_node(++tree_cnt); 32 if(!tree_2[x].rchild) tree_2[x].rchild=new_node(++tree_cnt); 33 //tree_2[tree_2[x].lchild].svalue+=(tree[x].mid-tree[x].sleft+1)*tree_2[x].delta; 34 //tree_2[tree_2[x].rchild].svalue+=(tree[x].sright-tree[x].mid)*tree_2[x].delta; 35 tree_2[tree_2[x].lchild].svalue+=(umid-uleft+1)*tree_2[x].delta; 36 tree_2[tree_2[x].rchild].svalue+=(uright-umid)*tree_2[x].delta; 37 tree_2[tree_2[x].lchild].delta+=tree_2[x].delta,tree_2[tree_2[x].rchild].delta+=tree_2[x].delta; 38 tree_2[x].delta=0; 39 } 40 void modify_2(int x,int _left,int _right,int uleft,int uright){ 41 int umid=(uleft+uright)>>1; 42 if(uleft==_left && uright==_right){ 43 tree_2[x].svalue+=uright-uleft+1,tree_2[x].delta++; 44 return ; 45 } 46 push_down(x,uleft,uright); 47 if(_left<=umid && _right>umid){ 48 modify_2(tree_2[x].lchild,_left,umid,uleft,umid); 49 modify_2(tree_2[x].rchild,umid+1,_right,umid+1,uright); 50 } 51 else if(_right<=umid) modify_2(tree_2[x].lchild,_left,_right,uleft,umid); 52 else modify_2(tree_2[x].rchild,_left,_right,umid+1,uright); 53 tree_2[x].svalue=tree_2[tree_2[x].lchild].svalue+tree_2[tree_2[x].rchild].svalue; 54 //这句忘了QAQ 55 //if(tree_2[x].svalue<_value) cout<<"fuck!!!"<<" "<<x<<endl; 56 } 57 void modify(int x,int y,int _left,int _right){ 58 modify_2(tree[x].root,_left,_right,1,n); 59 if(tree[x].sleft==tree[x].sright) return ; 60 if(y<=tree[x].mid) modify(x<<1,y,_left,_right); 61 else modify(x<<1|1,y,_left,_right); 62 } 63 long long query_2(int x,int _left,int _right,int uleft,int uright){ 64 int umid=(uleft+uright)>>1; 65 if(uleft==_left && uright==_right) return tree_2[x].svalue; 66 push_down(x,uleft,uright); 67 if(_left<=umid && _right>umid) 68 return query_2(tree_2[x].lchild,_left,umid,uleft,umid)+query_2(tree_2[x].rchild,umid+1,_right,umid+1,uright); 69 else if(_right<=umid) return query_2(tree_2[x].lchild,_left,_right,uleft,umid); 70 else return query_2(tree_2[x].rchild,_left,_right,umid+1,uright); 71 } 72 int query(int x,long long y,int _left,int _right){ 73 if(tree[x].sleft==tree[x].sright) return tree[x].sleft; 74 long long rchild_cnt=query_2(tree[x<<1|1].root,_left,_right,1,n); 75 if(y<=rchild_cnt) query(x<<1|1,y,_left,_right); 76 else query(x<<1,y-rchild_cnt,_left,_right); 77 } 78 int main(){//freopen("ddd.in","r",stdin); 79 cin>>n>>m; N=n<<1; 80 get_SegmentTree(1,0,N); 81 int _mark,_left,_right; long long _value; 82 while(m --> 0){//趋向于 83 _mark=read(),_left=read(),_right=read(),_value=read(); 84 if(_mark==1) modify(1,_value+n,_left,_right); 85 else printf("%d\n",query(1,_value,_left,_right)-n); 86 } 87 return 0; 88 }