这一题是the simple problem of integers的升级版,错了很多次。一开始我的思路是先放拦截的木板(木板先从低到高排序,因为高的会覆盖低的),然后依次读入木块,碰到混合的木块就继续向子树搜索,碰到同种颜色的木块就把加到这种颜色上,然后返回。但是这样如果颜色分的很杂的话,就会超时。所以我换了一种思路,先更新下落的木块,维护线段树的cnt和sum,cnt是延迟标志,表示这整段都要增加的长度,sum表示这段总的木块数(注意:这里的sum是实际的总覆盖数,也是加上cnt的覆盖数,即每次更新cnt的时候,sum也要更新,这里和the simple problem of integers,因为那题cnt更新的时候可以不用更新sum,只有pushdown的时候才要把cnt变为0,sum+=cnt*(r-l+1).但是这一题多了一个清0操作,即要使这一段的数都变为0,如果不记录实际长度,就会出错,这里sum[i]=sum[i*2]+sum[i*2+1]是重点.)然后这题很坑的地方就是内存不足,我MLE了10多次,最后把long long开成int,然后把线段树的左右标记去掉,写进函数,终于A了。= =
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define ll long long #define maxn 100010 int pos[4*maxn]; int a[maxn],d[maxn]; struct edge{ int l,r,h,id; ll num1; }c[maxn]; ll sum[16*maxn],cnt[16*maxn]; bool flag[16*maxn]; bool cmp1(edge a,edge b){ return a.h>b.h; } bool cmp2(edge a,edge b){ return a.id<b.id; } void build(int l,int r,int i) { int mid; cnt[i]=sum[i]=0;flag[i]=false; if(l==r)return; mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } void update1(int l,int r,int L,int R,int i) { int mid; if(L==l && R==r){ cnt[i]+=1; sum[i]+=(ll)(pos[r+1]-pos[l]); return; } mid=(L+R)/2; if(cnt[i]){ cnt[i*2]+=cnt[i]; cnt[i*2+1]+=cnt[i]; sum[i*2]+=cnt[i]*(ll)(pos[mid+1]-pos[L]); sum[i*2+1]+=cnt[i]*(ll)(pos[R+1]-pos[mid+1]); cnt[i]=0; } if(r<=mid)update1(l,r,L,mid,i*2); else if(l>mid)update1(l,r,mid+1,R,i*2+1); else{ update1(l,mid,L,mid,i*2); update1(mid+1,r,mid+1,R,i*2+1); } sum[i]=sum[i*2]+sum[i*2+1]; } void update2(int l,int r,int color,int L,int R,int i) { int mid; if(flag[i])return; if(l==L && R==r){ flag[i]=true; c[color].num1+=sum[i]; sum[i]=0; return; } mid=(L+R)/2; if(cnt[i]){ cnt[i*2]+=cnt[i]; cnt[i*2+1]+=cnt[i]; sum[i*2]+=cnt[i]*(ll)(pos[mid+1]-pos[L]); sum[i*2+1]+=cnt[i]*(ll)(pos[R+1]-pos[mid+1]); cnt[i]=0; } if(r<=mid)update2(l,r,color,L,mid,i*2); else if(l>mid)update2(l,r,color,mid+1,R,i*2+1); else{ update2(l,mid,color,L,mid,i*2); update2(mid+1,r,color,mid+1,R,i*2+1); } sum[i]=sum[i*2]+sum[i*2+1]; } int main() { int n,m,i,j,t,tot,t1,t2; while(scanf("%d%d",&n,&m)!=EOF) { t=0; for(i=1;i<=n;i++){ scanf("%d%d",&a[i],&d[i]); t++;pos[t]=a[i]; t++;pos[t]=d[i]; } for(i=1;i<=m;i++){ scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].h); c[i].id=i;c[i].num1=0; t++;pos[t]=c[i].l; t++;pos[t]=c[i].r; } sort(pos+1,pos+1+t); tot=1; for(i=2;i<=t;i++){ if(pos[i]!=pos[tot]){ tot++;pos[tot]=pos[i]; } } build(1,tot-1,1); for(i=1;i<=n;i++){ t1=lower_bound(pos+1,pos+1+tot,a[i])-pos; t2=lower_bound(pos+1,pos+1+tot,d[i])-pos; update1(t1,t2-1,1,tot-1,1); } sort(c+1,c+1+m,cmp1); for(i=1;i<=m;i++){ t1=lower_bound(pos+1,pos+1+tot,c[i].l)-pos; t2=lower_bound(pos+1,pos+1+tot,c[i].r)-pos; update2(t1,t2-1,c[i].id,1,tot-1,1); } for(i=1;i<=m;i++){ printf("%lld\n",c[i].num1); } printf("\n"); } return 0; }
ps:这题也可以先放砖块,然后放木板。思路是这样的:用线段树维护cnt(每段线段的增量),h(这一段的高度)。先把砖块更新,记录每一段的增量,然后把模板按从低到高排序,依次更新木板的高度,这里可以用成段更新,也可以不用,因为只要后面找每一个叶子节点到根节点的这一段路径中最大的高度就行了,然后用map把h和id连在一起,用于后面的更新。但这方法速度要慢90ms。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define ll long long #define maxn 100010 map<int,int>mp; map<int,int>::iterator it; int pos[4*maxn]; int a[maxn],d[maxn],h[16*maxn]; ll num1[maxn]; struct edge{ int l,r,h,id; }c[maxn]; ll cnt[16*maxn]; bool cmp1(edge a,edge b){ return a.h<b.h; } bool cmp2(edge a,edge b){ return a.id<b.id; } void build(int l,int r,int i) { int mid; cnt[i]=h[i]=0; if(l==r)return; mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } void update1(int l,int r,int L,int R,int i) { int mid; if(L==l && R==r){ cnt[i]+=1; return; } mid=(L+R)/2; if(cnt[i]){ cnt[i*2]+=cnt[i]; cnt[i*2+1]+=cnt[i]; cnt[i]=0; } if(r<=mid)update1(l,r,L,mid,i*2); else if(l>mid)update1(l,r,mid+1,R,i*2+1); else{ update1(l,mid,L,mid,i*2); update1(mid+1,r,mid+1,R,i*2+1); } } void update2(int l,int r,int color,int L,int R,int i) { int mid; if(l==L && R==r){ h[i]=color; return; } mid=(L+R)/2; if(cnt[i]){ cnt[i*2]+=cnt[i]; cnt[i*2+1]+=cnt[i]; cnt[i]=0; } if(r<=mid)update2(l,r,color,L,mid,i*2); else if(l>mid)update2(l,r,color,mid+1,R,i*2+1); else{ update2(l,mid,color,L,mid,i*2); update2(mid+1,r,color,mid+1,R,i*2+1); } } void question(int id,int ht,int L,int R,int i) { int mid; if(L==id && R==id){ ht=max(ht,h[i]); num1[mp[ht]]+=(ll)cnt[i]*(pos[R+1]-pos[R]); return; } ht=max(ht,h[i]); if(cnt[i]){ cnt[i*2]+=cnt[i]; cnt[i*2+1]+=cnt[i]; cnt[i]=0; } mid=(L+R)/2; if(id<=mid)question(id,ht,L,mid,i*2); else question(id,ht,mid+1,R,i*2+1); } int main() { int n,m,i,j,t,tot,t1,t2; while(scanf("%d%d",&n,&m)!=EOF) { t=0; for(i=1;i<=n;i++){ scanf("%d%d",&a[i],&d[i]); t++;pos[t]=a[i]; t++;pos[t]=d[i]; } for(i=1;i<=m;i++){ scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].h); c[i].id=i;num1[i]=0; t++;pos[t]=c[i].l; t++;pos[t]=c[i].r; mp[c[i].h]=c[i].id; } sort(pos+1,pos+1+t); tot=1; for(i=2;i<=t;i++){ if(pos[i]!=pos[tot]){ tot++;pos[tot]=pos[i]; } } build(1,tot-1,1); for(i=1;i<=n;i++){ t1=lower_bound(pos+1,pos+1+tot,a[i])-pos; t2=lower_bound(pos+1,pos+1+tot,d[i])-pos; update1(t1,t2-1,1,tot-1,1); } sort(c+1,c+1+m,cmp1); for(i=1;i<=m;i++){ t1=lower_bound(pos+1,pos+1+tot,c[i].l)-pos; t2=lower_bound(pos+1,pos+1+tot,c[i].r)-pos; update2(t1,t2-1,c[i].h,1,tot-1,1); } for(i=1;i<=tot-1;i++){ question(i,0,1,tot-1,1); } for(i=1;i<=m;i++){ printf("%lld\n",num1[i]); } printf("\n"); } return 0; }