【JZOJ5229】【GDOI2018模拟7.14】小奇的糖果
2017-07-14 21:28
381 查看
Description
有 N 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色。Data Constraint
对于 30% 的数据,N ≤ 100;对于 60% 的数据,N ≤ 5000;
对于 100% 的数据,N ≤ 100000,K ≤ 100000,T ≤ 3。
Solution
我们可以枚举哪颜色不选取。当你枚举一个颜色时,将该颜色按x轴从小到大排序,用单调队列求出一个点左上方的相同的颜色的横坐标。该点的左下方、右下方、右上方同理。以水平线段上方为例,我们可以以该点左上方纵坐标,右上方的纵坐标与该点横坐标的交点为线段的两个端点。求一次答案。求一个线段上方的点的数量,我们可以事先将所有点按纵坐标排序,然后依次插入主席树中。时间复杂度O(NlogN)。
PS.为什么有个全用线段树处理一个点左上右下的家伙会比我单调队列还快!!!
Code
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn=1e5+5; struct code{ int x,y,z,bz; }a[maxn],b[maxn]; struct code1{ int l,r,sum; }f[maxn*20]; int first[maxn],last[maxn],next[maxn],p[maxn],d[maxn],ul[maxn],ur[maxn],dl[maxn],dr[maxn]; int test,n,m,i,t,j,k,l,x,y,z,num,ans,num1,bz[maxn]; bool cmp(code x,code y){ return x.x<y.x || x.x==y.x && x.y<y.y; } bool cmp1(code x,code y){ return x.y<y.y; } void lian(int x,int y){ last[++num1]=y;next[num1]=first[x];first[x]=num1; } void insert(int l,int r,int &v,int x){ int mid=(l+r)/2; f[++num]=f[v];v=num; if (l==r){ f[v].sum++;return; } if (mid>=x) insert(l,mid,f[v].l,x); else insert(mid+1,r,f[v].r,x); f[v].sum=f[f[v].l].sum+f[f[v].r].sum; } void find(int l,int r,int v,int v1,int x,int y){ int mid=(l+r)/2; if (!v || f[v].sum==f[v1].sum) return; if (l>=x && r<=y){ t+=f[v].sum-f[v1].sum;return; } if (l<=y && mid>=x) find(l,mid,f[v].l,f[v1].l,x,y); if (mid<y && r>=x) find(mid+1,r,f[v].r,f[v1].r,x,y); } int main(){ // freopen("data.in","r",stdin); scanf("%d",&test); for (;test;test--){ ans=0;memset(bz,0,sizeof(bz)); memset(first,0,sizeof(first)); scanf("%d%d",&n,&m); for (i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); if (!bz[a[i].z]) t++; bz[a[i].z]=1; } if (t<m){ printf("%d\n",n);continue; } sort(a+1,a+n+1,cmp);num=0;t=a[1].x-1; for (i=1;i<=n;i++){ if (a[i].x!=t)num++; t=a[i].x;a[i].x=num; } sort(a+1,a+n+1,cmp1);num=0;t=a[1].y-1;num1=0; for (i=1;i<=n;i++){ if (a[i].y!=t)num++; t=a[i].y;a[i].y=num; lian(a[i].z,i); } j=1;num=0; for (i=1;i<=n;i++){ p[i]=p[i-1]; while (a[j].y<=i && j<=n) insert(1,n,p[i],a[j++].x); } for (i=1;i<=m;i++){ num=0; for (t=first[i];t;t=next[t]) b[++num]=a[last[t]]; sort(b+1,b+num+1,cmp); for (j=1;j<=num;j++){ while (b[d[d[0]]].y>b[j].y && d[0]) dr[d[d[0]--]]=b[j].x-1; if (b[d[d[0]]].y!=b[j].y) dl[j]=b[d[d[0]]].x+1; else dl[j]=dl[d[d[0]]]; d[++d[0]]=j; } while (d[d[0]]) dr[d[d[0]--]]=n; for (j=1;j<=num;j++){ while (b[d[d[0]]].y<b[j].y && d[0]) ur[d[d[0]--]]=b[j].x-1; if (b[d[d[0]]].y!=b[j].y) ul[j]=b[d[d[0]]].x+1; else ul[j]=dl[d[d[0]]]; d[++d[0]]=j; } while (d[d[0]]) ur[d[d[0]--]]=n; for (j=1;j<=num;j++){ if (b[j].x==b[j-1].x) continue;t=0; find(1,n,p[b[j].y-1],p[0],dl[j],dr[j]); ans=max(ans,t); } for (j=num;j>=1;j--){ if (b[j].x==b[j+1].x) continue;t=0; find(1,n,p ,p[b[j].y],ul[j],ur[j]); ans=max(ans,t); } for (j=1;j<=num;j++){ if (b[j].x==b[j-1].x)continue;t=0; find(1,n,p ,p[0],b[j-1].x+1,b[j].x-1); ans=max(ans,t); } t=0; find(1,n,p ,p[0],b[num].x+1,n); ans=max(ans,t); } printf("%d\n",ans); } }
相关文章推荐
- 【JZOJ 5229】【GDOI2018模拟7.14】小奇的糖果
- 【GDOI2018模拟7.14】小奇的糖果 树状数组+扫描线
- [bzoj4548]【GDOI2018模拟7.14】小奇的糖果
- 【GDOI2018模拟7.14】小奇的糖果
- 【jozj5228】【GDOI2018模拟7.14】【小奇的集合】【矩阵乘法】
- JZOJ5228. 【GDOI2018模拟7.14】小奇的集合
- JZOJ 5221. 【GDOI2018模拟7.10】A
- JZOJ5242【GDOI2018模拟8.8】矩阵
- 【JZOJ5237】【GDOI2018模拟8.7】最长公共子序列
- 【JZOJ5270】【GDOI2018模拟8.14】神奇的矩阵
- 【jzoj5221】【GDOI2018模拟7.10】【A】【线段树合并】
- 【JZOJ5238】【GDOI2018模拟8.7】的士碰撞
- 【JZOJ5260】【GDOI2018模拟8.12】区间第k小(分块)
- JZOJ5365. 【GDOI2018模拟9.14】通信 线段树+重链剖分
- 【jzoj5215】【BZOJ4870】【Shoi2017】【GDOI2018模拟7.9】【组合数问题】【矩阵快速幂】
- 【jzoj5219】【GDOI2018模拟7.10】【B】【动态规划】
- 【JZOJ 5215】【GDOI2018模拟7.9】组合数问题
- jzoj5220 【GDOI2018模拟7.10】C (双序列dp)
- 【JZOJ5262】【GDOI2018模拟8.12】树(DP,性质题)
- [JZOJ5239]. 【GDOI2018模拟8.7】图的异或