【JZOJ5296】【清华集训模拟】Sequence(整体二分)

来源:互联网 发布:极客学院java百度网盘 编辑:程序博客网 时间:2024/06/10 21:18

Description

这里写图片描述

Solution

这是第一次打整体二分。是一道十分裸的整体二分。
整体二分大致思想就是,对于一坨询问,我们二分一个值,然后对所有的询问都进行判断,然后分别放到[l,mid]和[mid+1,r],这要每次枚举的区间都是[l,r]的话,时间复杂度就是log的。
首先排名[x,y]的可以用主席树来搞出它的值域范围。
我们对于b的答案二分一个值mid。然后找到所有b的值小于mid(这个可以对一开始的数组排个序,然后选择的区间都是连续的一段,因为是个排列,新加入的连续一段[l,mid])。然后我们用树状数组统计一下在值域内的个数是否小于等于k(这个就是一个二维偏序),然后在判断哪些个数是小于等于它的k的,是就往[l,mid]走,否则[mid+1,r]。树状数组的清空直接把所有用过的数再倒着做一次,就是-1。
时间复杂度O(nlog^2)

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=2e5+7;int i,j,k,l,n,m,ans,an[maxn],o,kk[maxn],xx[maxn],yy[maxn],d[maxn],hhh;struct node{    int l,r,c,o;}c[maxn],g[maxn],q[maxn];bool cmp(node x,node y){return x.r<y.r;}bool cmp1(node x,node y){return x.r<y.r;}struct nod{    int l,r,sum;}tt[maxn*40];int a[maxn],b[maxn],root[maxn],num,t[maxn],tot,tmp,e[maxn],f[maxn];void insert(int &x,int y,int l,int r,int z){    x=++num;tt[x]=tt[y];    if(l==r){tt[x].sum++;return;}    int mid=(l+r)/2;    if(z<=mid)insert(tt[x].l,tt[y].l,l,mid,z);    else insert(tt[x].r,tt[y].r,mid+1,r,z);    tt[x].sum=tt[tt[x].l].sum+tt[tt[x].r].sum;}int find1(int x,int y,int l,int r,int k){    if(l==r)return l;    int mid=(l+r)/2;    if(tt[tt[x].l].sum-tt[tt[y].l].sum>=k)return find1(tt[x].l,tt[y].l,l,mid,k);    else return find1(tt[x].r,tt[y].r,mid+1,r,k-tt[tt[x].l].sum+tt[tt[y].l].sum);}void add(int x,int y){    for(;x<=n;x+=(x&-x))t[x]+=y;}int find(int x){    int z=0;if(!x)return 0;    for(;x;x-=(x&-x))z+=t[x];    return z;}void solve(int l,int r,int l1,int r1){    int i,j,mid;    if(l>r)return;    if(l1==r1){        fo(i,l,r)an[c[i].c]=l1;        return;    }    mid=(l1+r1)/2;    fo(i,l1,mid)d[i]=q[i].c;sort(d+l1,d+mid+1);    o=0;fo(i,l,r)g[++o]=c[i],g[o].o=1,g[++o]=c[i],g[o].o=-1,g[o].r=g[o].l-1,f[c[i].c]=e[c[i].c];    sort(g+1,g+1+o,cmp);    j=1;    fo(i,l1,mid){        while(j<=o&&g[j].r<d[i])        e[g[j].c]+=(find(yy[g[j].c])-find(xx[g[j].c]-1))*g[j].o,j++;        if(a[d[i]]==0){            ans=ans;        }        add(a[d[i]],1);    }    while(j<=o)e[g[j].c]+=(find(yy[g[j].c])-find(xx[g[j].c]-1))*g[j].o,j++;    fo(i,l1,mid)add(a[d[i]],-1);    tmp=l-1;    fo(i,l,r){        if(e[c[i].c]>=kk[c[i].c])g[++tmp]=c[i];    }    int u=tmp;    fo(i,l,r)if(e[c[i].c]<kk[c[i].c])g[++tmp]=c[i];else e[c[i].c]=f[c[i].c];    fo(i,l,r){        c[i]=g[i];    }    solve(l,u,l1,mid);    solve(u+1,r,mid+1,r1);}int main(){    freopen("sequence.in","r",stdin);    freopen("sequence.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)scanf("%d",&a[i]),insert(root[i],root[i-1],1,n,a[i]);    fo(i,1,n)scanf("%d",&b[i]),q[i].l=a[i],q[i].r=b[i],q[i].c=i;    sort(q+1,q+1+n,cmp1);    scanf("%d",&m);    fo(i,1,m){        scanf("%d%d%d%d%d",&c[i].l,&c[i].r,&xx[i],&yy[i],&kk[i]);c[i].c=i;        xx[i]=find1(root[c[i].r],root[c[i].l-1],1,n,xx[i]);        yy[i]=find1(root[c[i].r],root[c[i].l-1],1,n,yy[i]);    }    solve(1,m,1,n);    fo(i,1,m)printf("%d\n",an[i]);}
原创粉丝点击