标签:线段树
Time Limit: 3 Seconds Memory Limit: 32768 KB这一题是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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:线段树
原文地址:http://blog.csdn.net/kirito_acmer/article/details/47314181