[BZOJ3110]K大数查询|线段树套线段树
发布时间:2020-12-14 02:38:13 所属栏目:大数据 来源:网络整理
导读:妈呀这题好神好神好神。。我发现主席树好像做不了呀。。咋全写的是线段树套线段树呢。。后来还是看黄学长的代码看懂了。。果然我是看黄学长博客长大的。。有两种做法,大部分人是外层权值线段树,内层区间线段树,这个我写了,还是很好写。。 lyd 给了一种外
妈呀这题好神好神好神。。我发现主席树好像做不了呀。。咋全写的是线段树套线段树呢。。后来还是看黄学长的代码看懂了。。果然我是看黄学长博客长大的。。有两种做法,大部分人是外层权值线段树,内层区间线段树,这个我写了,还是很好写。。lyd给了一种外层区间内层权值的做法,没看懂。。内层区间[l1,r1]在外层权值区间[l,r]下的意义是在[l1,r1]内有多少权值在[l,r]之间的数。。由于一开始是空的,每次最多访问nlog^2 n个节点,所以我们用实时开点,空间复杂度O(nlog^2 n)。。具体的还是好好看代码。。
#include<iostream> #include<cstdio> #define N 200005 using namespace std; int n,m,opt,a,b,c,i,nd=0,root[N],lc[100*N],rc[100*N],sum[100*N],tag[100*N]; void mark(int &x,int l,int r,int c) { if (!x) x=++nd,lc[x]=rc[x]=tag[x]=sum[x]=0; tag[x]+=c;sum[x]+=c*(r-l+1); } void down(int x,int r) { if (!tag[x]||l==r) return; mark(lc[x],l,(l+r)>>1,tag[x]);mark(rc[x],((l+r)>>1)+1,r,tag[x]); tag[x]=0; } void update(int &x,int a,int b) { if (!x) x=++nd,lc[x]=rc[x]=tag[x]=sum[x]=0; down(x,r); if (l==a&&r==b) { tag[x]++;sum[x]+=b-a+1; return; } int mid=(l+r)>>1; if (b<=mid) update(lc[x],mid,b); else if (a>mid) update(rc[x],mid+1,b); else update(lc[x],mid),update(rc[x],b); sum[x]=sum[lc[x]]+sum[rc[x]]; } void insert(int a,int b,int c) { int now=1,l=1,r=n,mid; while (l<r) { update(root[now],1,n,b); mid=(l+r)>>1;now<<=1; if (c<=mid) r=mid; else l=mid+1,now+=1; } update(root[now],b); } int query(int x,int b) { if (!x) return 0; down(x,r); if (l==a&&r==b) return sum[x]; int mid=(l+r)>>1; if (b<=mid) return query(lc[x],b); else if (a>mid) return query(rc[x],b); else return query(lc[x],mid)+query(rc[x],b); } int solve(int a,int k) { int now=1,s; while (l<r) { int mid=(l+r)>>1;now<<=1; s=query(root[now],b); if (s>=k) r=mid;else l=mid+1,now++,k-=s; } return l; } int main() { freopen("3110.in","r",stdin); freopen("3110.out","w",stdout); scanf("%d%d",&n,&m); for (i=1;i<=N-1;i++) root[i]=0; while (m--) { scanf("%d%d%d%d",&opt,&a,&b,&c); if (opt==1) insert(a,n-c+1); else printf("%dn",n-solve(a,c)+1); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |