标签:add eof art 求逆 ems repeat source world put
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6018 Accepted Submission(s): 2620
题意:给一些数,数中有重复的。还有一些询问,问的是[L,R] 区间内有多少个数小于h,有多次询问。
思路:普通方法的话肯定会超时,题目问[L,R]区间内小于h的数有多少个,则可以算出cal(R) 和 cal(L - 1), 两者相减就是答案。这类问题和求逆序数的问题非常类似,即求一个数前面有几个数比它小。求逆序数的问题可以用树状数组解决。
然而我不想用树状数组写。据说是主席树的裸题,
然后就这样了
//自己写的没调出来的WA代码 #include<cstdio> #include<cstring> #include<algorithm> #include<map> #define m(s) memset(s,0,sizeof s) using namespace std; const int N=1e5+10; const int M=N*20; int n,m,T,sum[M],ls[M],rs[M]; int root[N],a[N],b[N],sz; map<int,int>ys; void build(int &k,int l,int r){ k=++sz; sum[k]=0; if(l==r) return ; int mid=l+r>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); } void insert(int &k,int last,int l,int r,int pos,int val){ k=++sz; ls[k]=ls[last]; rs[k]=rs[last]; sum[k]=sum[last]+val; if(l==r) return ; int mid=l+r>>1; if(pos<=mid) insert(ls[k],ls[last],l,mid,pos,val); else insert(rs[k],rs[last],mid+1,r,pos,val); } int query(int x,int y,int l,int r,int pos){ int mid=l+r>>1; if(l==r) return sum[y]-sum[x]; else if(pos<=mid) return query(ls[x],ls[y],l,mid,pos); else return sum[ls[y]]-sum[ls[x]]+query(rs[x],rs[y],mid+1,r,pos); } void Cl(){ sz=0;m(root);m(ls);m(rs);m(sum);m(a);m(b); } int main(){ int T,cas=1; for(scanf("%d",&T);cas<=T;cas++){ scanf("%d%d",&n,&m);printf("Case %d:\n",cas); for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); int cnt=unique(b+1,b+n+1)-(b+1); for(int i=1;i<=cnt;i++) ys[b[i]]=i; Cl();build(root[0],1,cnt); for(int i=1;i<=n;i++) insert(root[i],root[i-1],1,cnt,ys[a[i]],1); for(int i=1,l,r,h;i<=m;i++){ scanf("%d%d%d",&l,&r,&h);l++;r++; int k=upper_bound(b+1,b+cnt+1,h)-(b+1); if(k) printf("%d\n",query(root[l-1],root[r],1,cnt,k)); else puts("0"); } } return 0; }
//面向STD的源码 #include<bits/stdc++.h> using namespace std; const int N=100010; int n,m,a[N],b[N]; map<int,int>ys; struct Tree{ int ls,rs,sum; }tree[N*20]; int root[N],sz; int build(int l,int r){ int o=++sz; tree[o].sum=0; if(l == r) return o; int mid=(l+r)>>1; tree[o].ls=build(l,mid); tree[o].rs=build(mid+1,r); return o; } int insert(int x,int l,int r,int lt,int v){ int o=++sz; tree[o]=tree[lt]; tree[o].sum+=v; if(l==r) return o; int mid=(l+r)>>1; if(x<=mid) tree[o].ls=insert(x,l,mid,tree[lt].ls,v); else tree[o].rs=insert(x,mid+1,r,tree[lt].rs,v); return o; } int query(int i,int j,int x,int l,int r){ if(l==r) return tree[i].sum-tree[j].sum; int mid=(l+r)>>1,ret=0; if(x <= mid) ret+=query(tree[i].ls,tree[j].ls,x,l,mid); else{ ret+=tree[tree[i].ls].sum-tree[tree[j].ls].sum; ret+=query(tree[i].rs,tree[j].rs,x,mid+1,r); } return ret; } int main(){ int T,tCase=0;scanf("%d",&T); while(T--){ printf("Case %d:\n",++tCase); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); int cnt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=cnt;i++) ys[b[i]]=i; sz=0;root[0]=build(1,cnt); for(int i=1;i<=n;i++) root[i]=insert(ys[a[i]],1,cnt,root[i-1],1); for(int i=1,l,r,h;i<=m;i++){ scanf("%d%d%d",&l,&r,&h);r++;l++; int k=upper_bound(b+1,b+cnt+1,h)-b-1; if(k) printf("%d\n",query(root[r],root[l-1],k,1,cnt)); else printf("0\n"); } } return 0; }
标签:add eof art 求逆 ems repeat source world put
原文地址:http://www.cnblogs.com/shenben/p/6274560.html