BZOJ 3110 [Zjoi2013]K大数查询
来源:互联网 发布:java不兼容的类型 编辑:程序博客网 时间:2024/04/30 04:10
title: ‘BZOJ 3110 [Zjoi2013]K大数查询’
categories: BZOJ
date: 2016-2-3 00:00:00
tags: [树套树,整体二分]
Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果。
Sample
input.txt
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
output.txt
1
2
1
Solution
好久没更博客了。。
首先这题一个位置可以加多个数,一开始没有看懂题意很坑爹。。。
这样一来,我们可以对开一个二维线段树,外层是权值线段树,内层是区间线段树。这样做的意义是,对每一个权值的区间都用一个线段树来维护其出现的位置和次数。因为树套树太耗内存了,还是在修改的时候新建节点比较好。。。
在外层那颗线段树写类似于二分的非递归就好了,因为并不需要用子节点来更新他的信息。
还有因为我太弱了所以并没有写标记永久化……感觉要去学习一下新姿势了。
感觉一般可以用树套树做的题目整体二分也是可以的?权值那层线段树只需要二分就好了,然后再用一个线段树来处理整体二分时候对询问信息的处理。
Code 1:树套树
#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn (50000+5)#define maxm (5000000+5)using namespace std;struct Seg_Tree{ int lc,rc,sum,tag;}tr[maxm<<2];int root[maxn<<2];int n,m,cnt;inline int in(){ int x=0; char ch=getchar(); while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x;}void Update(int ind){ tr[ind].sum=tr[tr[ind].lc].sum+tr[tr[ind].rc].sum;}void Pushdown(int ind,int l,int r){ if(tr[ind].tag && l!=r){ if(!tr[ind].lc) tr[ind].lc=++cnt; if(!tr[ind].rc) tr[ind].rc=++cnt; int L=tr[ind].lc,R=tr[ind].rc,m=(l+r)>>1; tr[L].tag+=tr[ind].tag; tr[R].tag+=tr[ind].tag; tr[L].sum+=tr[ind].tag*(m-l+1); tr[R].sum+=tr[ind].tag*(r-m); } tr[ind].tag=0; }void Modify(int &ind,int l,int r,int ql,int qr){ if(!ind) ind=++cnt; Pushdown(ind,l,r); if(l==ql && r==qr){ tr[ind].sum+=(r-l+1); tr[ind].tag++; return; } int mid=(l+r)>>1; if(qr<=mid) Modify(tr[ind].lc,l,mid,ql,qr); else if(ql>mid) Modify(tr[ind].rc,mid+1,r,ql,qr); else Modify(tr[ind].lc,l,mid,ql,mid),Modify(tr[ind].rc,mid+1,r,mid+1,qr); Update(ind);}int Getsum(int ind,int l,int r,int ql,int qr){ if(!ind) return 0; Pushdown(ind,l,r); if(l==ql && r==qr) return tr[ind].sum; int mid=(l+r)>>1,tmp; if(qr<=mid) tmp=Getsum(tr[ind].lc,l,mid,ql,qr); else if(ql>mid) tmp=Getsum(tr[ind].rc,mid+1,r,ql,qr); else tmp=Getsum(tr[ind].lc,l,mid,ql,mid)+Getsum(tr[ind].rc,mid+1,r,mid+1,qr); Update(ind); return tmp;}void Insert(int a,int b,int c){ int l=1,r=n,ind=1; while(l<r){ Modify(root[ind],1,n,a,b); int mid=(l+r)>>1; if(c<=mid) r=mid,ind=ind<<1; else l=mid+1,ind=ind<<1|1; } Modify(root[ind],1,n,a,b);}int Query(int a,int b,int c){ int l=1,r=n,ind=1; while(l<r){ int mid=(l+r)>>1; int s=Getsum(root[ind<<1],1,n,a,b); if(s>=c) r=mid,ind=ind<<1; else l=mid+1,ind=ind<<1|1,c-=s; } return l;}int main(){ n=in(); m=in(); for(int i=1;i<=m;i++){ int opt,a,b,c; opt=in(); a=in(); b=in(); c=in(); if(opt==1) Insert(a,b,n-c+1); else printf("%d\n",n-Query(a,b,c)+1); } return 0; }
Code 2:整体二分
#include<cstdio>#include<climits>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn 50000+5using namespace std;struct Seg_Tree{ int l,r,mem; int tag,sum,sz; }tr[maxn<<4];struct Query{ int ct,l,r,c,pos,k;}q[maxn]; int res[maxn];int n,m;bool cmp(const Query &s,const Query &b){ return s.k<b.k;}void Update(int k){ tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;}void Pushdown(int k){ int l=k<<1,r=k<<1|1; if(tr[k].mem){ tr[l].tag=tr[r].tag=tr[l].sum=tr[r].sum=0; tr[l].mem=tr[r].mem=1; tr[k].mem=0; } if(tr[k].tag){ tr[l].sum+=tr[k].tag*(tr[l].r-tr[l].l+1); tr[r].sum+=tr[k].tag*(tr[r].r-tr[r].l+1); tr[l].tag+=tr[k].tag; tr[r].tag+=tr[k].tag; tr[k].tag=0; }}void Build(int l,int r,int k){ tr[k].l=l; tr[k].r=r; if(l==r) return; int mid=(l+r)>>1; Build(l,mid,k<<1); Build(mid+1,r,k<<1|1);}void Add(int l,int r,int val,int k){ Pushdown(k); if(tr[k].l==l && tr[k].r==r){ tr[k].tag+=val; tr[k].sum+=val*(r-l+1); return; } if(r<=tr[k<<1].r) Add(l,r,val,k<<1); else if(l>=tr[k<<1|1].l) Add(l,r,val,k<<1|1); else Add(l,tr[k<<1].r,val,k<<1),Add(tr[k<<1|1].l,r,val,k<<1|1); Update(k);}int Getsum(int l,int r,int k){ Pushdown(k); if(tr[k].l==l && tr[k].r==r) return tr[k].sum; if(r<=tr[k<<1].r) return Getsum(l,r,k<<1); else if(l>=tr[k<<1|1].l) return Getsum(l,r,k<<1|1); else return Getsum(l,tr[k<<1].r,k<<1)+Getsum(tr[k<<1|1].l,r,k<<1|1);}void solve(int l,int r,int x,int y){ if(l==r){ for(int i=x;i<=y;i++) if(q[i].ct==2) res[q[i].pos]=l; return; } int mid=(l+r)>>1,pl=0,pr=y-x+1; tr[1].mem=1; tr[1].tag=tr[1].sz=tr[1].sum=0; for(int i=x;i<=y;i++) if(q[i].ct==1){ if(q[i].c<=mid) q[i].k=++pl; else{ Add(q[i].l,q[i].r,1,1); q[i].k=++pr; } } else{ int sum=Getsum(q[i].l,q[i].r,1); if(sum<q[i].c){ q[i].k=++pl; q[i].c-=sum; } else q[i].k=++pr; } sort(q+x,q+y+1,cmp); solve(l,mid,x,x+pl-1); solve(mid+1,r,x+pl,y);}int main(){ freopen("3110.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&q[i].ct,&q[i].l,&q[i].r,&q[i].c); q[i].pos=i; } Build(1,n,1); solve(0,n,1,m); for(int i=1;i<=m;i++) if(res[i]) printf("%d\n",res[i]); return 0;}
0 0
- BZOJ 3110 ZJOI2013 K大数查询 树套树
- BZOJ-3110-K大数查询-ZJOI2013-暴力
- bzoj 3110 [Zjoi2013]K大数查询
- BZOJ 3110 [Zjoi2013]K大数查询
- 【bzoj 3110】[Zjoi2013]K大数查询|树套树
- BZOJ 3110 [Zjoi2013]K大数查询
- 【34.14%】【BZOJ 3110】 [Zjoi2013]K大数查询
- [BZOJ]3110: [Zjoi2013]K大数查询
- BZOJ-3110-K大数查询-ZJOI2013-整体二分
- bzoj 3110: [Zjoi2013]K大数查询(树套树,整体二分)
- bzoj 3110: [Zjoi2013]K大数查询(树套树)
- [BZOJ]3110: [Zjoi2013]K大数查询 整体二分+线段树
- bzoj 3110 [Zjoi2013]K大数查询 整体二分
- 3110 [Zjoi2013]K大数查询
- 3110: [Zjoi2013]K大数查询
- 3110: [Zjoi2013]K大数查询
- 3110: [Zjoi2013]K大数查询
- 3110: [Zjoi2013]K大数查询
- 简易php博客(6)_后台修改
- Java自定义注解的实现
- LeetCode:String to Integer (atoi)
- Activity
- 0-时间复杂度&空间复杂度的计算
- BZOJ 3110 [Zjoi2013]K大数查询
- Latex 入门
- 在QWidget 窗口上弹出右键菜单
- JAVA之内部类--成员内部类- 静态内部类- 方法内部类- 匿名内部类
- maven assembly plugin
- LLDB命令详解(自用备忘)
- JSP中JQuery UI Dialog弹窗使用具体操作
- kalman 滤波 演示与opencv代码
- log4j:WARN Please initialize the log4j system properly