CF 12D BALL 线段树 && 树状数组
http://codeforces.com/problemset/problem/12/D
线段树
View Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf = ~0u>>2; const int N = 500010; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int Max[N<<2]; struct node{ int x,y,z; }in[N]; int tot,n; int num[N]; int max(int a,int b){ return a>b?a:b; } void pushup(int rt){ Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); } void build(int l,int r,int rt){ Max[rt]=0; if(l==r) return ; int m=(l+r)>>1; build(lson); build(rson); } void update(int p,int val,int l,int r,int rt){ if(l==r){ if(val>Max[rt]) Max[rt]=val; return ; } int m=(l+r)>>1; if(p<=m) update(p,val,lson); else update(p,val,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) return Max[rt]; int m=(l+r)>>1; int ret=0; if(L<=m) ret=max(ret,query(L,R,lson)); if(R>m) ret=max(ret,query(L,R,rson)); return ret; } void init(){ sort(num+1,num+n+1); tot=unique(num+1,num+n+1)-num-1; build(1,tot,1); for(int i=1;i<=n;i++) in[i].x=lower_bound(num+1,num+1+tot,in[i].x)-num; } inline int cmp(node a,node b){ return a.y>b.y; } int main() { int i,j,k; scanf("%d",&n); for(i=1;i<=n;i++) {scanf("%d",&in[i].x); num[i]=in[i].x;} for(i=1;i<=n;i++) scanf("%d",&in[i].y); for(i=1;i<=n;i++) scanf("%d",&in[i].z); init(); sort(in+1,in+n+1,cmp); int ans=0; for(i=1;i<=n;i=j){ for(j=i;j<=n&&in[j].y==in[i].y;j++){ int z; z=query(in[j].x+1,tot,1,tot,1); if(z>in[j].z) ans++; } for(;i<=j-1;i++) update(in[i].x,in[i].z,1,tot,1); } printf("%d\n",ans); return 0; } /* 3 1 3 5 2 4 6 3 5 7 */
树状数组
View Code
/* CF 12D 树状数组好题 给你n个整数三元组, 对于某个三元组,判断是否存在一个三元组的元素都大于这个三元组 题目给三个数,必然有其道理 可以把其中一个数离散化当做树状数组的下标,再按照另外某个数排序 最后就只需利用树状数组数组处理好最后一个数就行了 具体做法: 比如对x离散化 对y降序排序 x当做树状数组的下标 每次把y值相同的三元组一起拿出来处理 因为前面加进树状数组的数的y值肯定比现在这个数的y值要大,这一个数就不必考虑了 然后就是找前面加进树状数组的数中有没有z坐标 大于 当前枚举的数的z坐标,当然是在大于x的区间内 这里与树状数组的功能相反了,这里树状数组是求前n项中的最大值,而题目要求下标在x->n间的最大值 转换一下就好了 离散化前:1 3 5 7 9 离散化后并不是1 2 3 4 5 要倒过来:5 4 3 2 1 那么小于x的区间实际上就是大于x的区间 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 500010; int c[N]; int num[N]; int n; struct node{ int x,y,z; }in[N]; inline void Max(int &a,int b){ if(a<b) a=b; } void update(int x,int d){ for(;x<N;x+=x&-x) Max(c[x],d); } int sum(int x){ int ans=0; for(;x>0;x-=x&-x) Max(ans,c[x]); return ans; } void init(){ sort(num+1,num+n+1); int tot=unique(num+1,num+n+1)-num-1; for(int i=1;i<=n;i++) in[i].x=tot-(lower_bound(num+1,num+1+tot,in[i].x)-num-1); //把x的相对大小倒了过来 所以小于in[i].x实际表示大于in[i].x;,便于树状数组的sum操作 } inline int cmp(node a,node b){ return a.y>b.y; } int main() { int i,j,k; scanf("%d",&n); for(i=1;i<=n;i++) {scanf("%d",&in[i].x); num[i]=in[i].x;} for(i=1;i<=n;i++) scanf("%d",&in[i].y); for(i=1;i<=n;i++) scanf("%d",&in[i].z); init(); memset(c,0,sizeof(c)); sort(in+1,in+n+1,cmp); int ans=0; for(i=1;i<=n;i=j){ for(j=i;j<=n&&in[j].y==in[i].y;j++){ int z=sum(in[j].x-1); if(z>in[j].z) ans++; } for(;i<=j-1;i++) update(in[i].x,in[i].z); } printf("%d\n",ans); return 0; } /* 3 1 3 5 2 4 6 3 5 7 */