ZOJ 3299 线段树 离散化
本来是个很简单的题目,难住我的主要是这么几点
1.它所有的点都是坐标,不是实际的砖块,1,3指的是1-2 2-3的砖块。。。后来就是用1 代表1-2 ,2代表2-3.。。。。,这样的话,每次读入的数据,都把r--
就行,然后在实际的砖块数就是 x[r+1]-x[l]。
2.我动手太快,没想清楚它是叠层型,即每次读入砖块坐标,都是往原有砖块的基础上++,这样的话,懒惰标记,就也一定是每次++,这里我WA了好久,一开始没想清楚,没按叠层来更新懒惰标记。。
3.有个地方超级难以想到,就是在最后query木板能承载多少砖块的时候,用个flag标记好已经完全清空的node,因为询问有多次,下次再遇到这个node的时候,直接return 0,我一开始没想明白,觉得这个去掉也没关系。。后来发现,因为延迟标记的问题某个节点如果被清空,其子节点可能尚未更新,而且延迟非常严重,可能连初始的砖块都还没更新,弄个极端的例子,直接初始落下砖块1-8,然后只有最顶上的节点有砖块,底下全没有,这个时候你开始插入板子,第一次访问1-8,肯定是正确的结果,再次插板访问1-8中的某一个节点,比如5-8,此时它连上一次的砖块落下那个延迟标记都还没更新,你即便pushdown了,也是第一次插板1-8之前的状态了,绝逼是错的啊。所以我试了好多次,终于明白这个确实是关键。
4.其实离散化反而在这个题目里面很不起眼了,就是最普通的离散化,而且中间不必手动插点也能过。。当然还是手动插一插比较好
5.这个题目卡内存超级BT啊。。我就多开了那么一些,就MLE,少开了一点,就SF越界,我简直无语啊。。
改来改去,代码写的真心挫。。。求不喷。。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define N 110010 using namespace std; long long d[N*18]; bool flag[N*18]; int pd[N*18]; int a[N],b[N]; int x[N*8]; struct node { int ax; int bx; int h; int id; long long ans; } bd[N]; void getup(int rt) { d[rt]=d[rt<<1]+d[rt<<1|1]; } void build(int rt,int l,int r) { d[rt]=0; flag[rt]=false; pd[rt]=0; if (l>=r) { return; } int mid=(l+r)>>1; build(lson); build(rson); //getup(rt); } void pushdown(int rt,int l,int r) { if (l>=r) return; int ll=rt<<1,rr=rt<<1|1; int mid=(l+r)>>1; pd[ll]+=pd[rt]; pd[rr]+=pd[rt]; d[ll]+=(long long)pd[rt]*(x[mid+1]-x[l]); d[rr]+=(long long)pd[rt]*(x[r+1]-x[mid+1]); pd[rt]=0; } void fix(int L,int R,int col,int rt,int l,int r) { if (L<=l && r<=R) { d[rt]+=(long long)(x[r+1]-x[l]); pd[rt]+=col; return; } pushdown(rt,l,r); int mid=(l+r)>>1; if (L<=mid) fix(L,R,col,lson); if (R>mid) fix(L,R,col,rson); getup(rt); } long long query(int L,int R,int rt,int l,int r) { if (flag[rt]) return 0;//这里是关键,详见要点3 if (L<=l && r<=R) { flag[rt]=true; long long temp; temp=d[rt]; d[rt]=0; pd[rt]=0; return temp; } pushdown(rt,l,r); int mid=(l+r)>>1; long long ret=0; if (L<=mid) ret+=query(L,R,lson); if (R>mid) ret+=query(L,R,rson); getup(rt); return ret; } int bs(int data,int l,int r) { int mid; while (l<r) { mid=(l+r)>>1; if (x[mid]==data) return mid; if (x[mid]<data) l=mid+1; else r=mid; } return l; } bool cmp(node a,node b) { return a.h>b.h; } bool cmp2(node a,node b) { return a.id<b.id; } int main() { int n,m; while (scanf("%d%d",&n,&m)!=EOF) { int i,j; int mcur=0; for (i=1; i<=n; i++) { scanf("%d%d",&a[i],&b[i]); if (a[i]>b[i]) { int tt=a[i]; a[i]=b[i]; b[i]=tt; } //b[i]--; x[++mcur]=a[i]; x[++mcur]=b[i]; } for (j=1; j<=m; j++) { scanf("%d%d%d",&bd[j].ax,&bd[j].bx,&bd[j].h); bd[j].id=j; if (bd[j].ax>bd[j].bx) { int t2=bd[j].ax; bd[j].ax=bd[j].bx; bd[j].bx=t2; } //bd[j].bx--; x[++mcur]=bd[j].ax; x[++mcur]=bd[j].bx; } sort(x+1,x+1+mcur); int cur=1; for (i=2; i<=mcur; i++) { if (x[i]!=x[i-1]) x[++cur]=x[i]; } int temp=cur; for (i=2; i<=temp; i++) { if (x[i]-x[i-1]>1) x[++cur]=x[i-1]+1; //if (x[i]-x[i-1]>2) x[++cur]=x[i]-1; } sort(x+1,x+1+cur); //for (i=1; i<=cur; i++) // cout<<i<<" "<<x[i]<<endl; build(1,1,cur); int fa,fb; for (i=1; i<=n; i++) { fa=bs(a[i],1,cur); fb=bs(b[i],1,cur); if (fa>fb){ int t3=fa; fa=fb; fb=t3; } if (fb>fa) fb--; fix(fa,fb,1,1,1,cur); } //cout<<"Pass"<<endl; sort(bd+1,bd+1+m,cmp); for (i=1; i<=m; i++) { fa=bs(bd[i].ax,1,cur); fb=bs(bd[i].bx,1,cur); if (fa>fb){ int t4=fa; fa=fb; fb=t4; } if(fb>fa) fb--; long long tt=query(fa,fb,1,1,cur); bd[i].ans=tt; } //cout<<"Pass2"<<endl; sort(bd+1,bd+1+m,cmp2); for (j=1; j<=m; j++) { printf("%lld\n",bd[j].ans); } putchar('\n'); } return 0; }