zoukankan      html  css  js  c++  java
  • zoj3299 Fall the Brick

    Time Limit: 3 Seconds      Memory Limit: 32768 KB
    Now the God is very angry, so he wants to punish the lazy, greedy humans. He chooses to throw some lines of bricks (just down from the very high Heaven). These days the God lives in a 2D world, so he just throw the bricks in a vertical plane. Each time, the God throws a line of bricks. The width of each brick is 1, and the length will be given.


    t__nt is a hero in the world and he is trying his best to save the world. Now he has made m horizontal boards in the air with his magic power to stop the bricks. If one brick falls onto a board, it can not fall down any more. Notice that, for a line of bricks, consecutive bricks are not connected. So when some bricks touch a board, the others will continues to fall down. Now, t__nt wants to know how many bricks each board holds after the God's crazy action. He asks you, an ACMer, to help him.




    Input


    There are no more then 10 cases. There is a blank line between consecutive cases. The first line of each case contains two integers n, m (0 < n, m <= 100000), indicating the number of lines of bricks and number of horizontal boards made by t__nt. n lines follow, each contains two integers li, ri (0 <= li < ri <= 30000000). li and ri is the x-coordinates for the left side and the right side of the line of bricks. m lines follow, each contains three integers ai, bi, and hi (0 <= ai < bi <= 30000000; 0 < hi < 1000000000), which means that board i is at height hi and the extreme points are ai and bi. You may assume no two boards with same height will overlap with each other.


    Output


    For each case, print m lines. The ith line means the number of bricks on board i at last. Print a blank line after each case.


    Sample Input


    1 2
    1 8
    1 5 8
    3 7 6
    Sample Output


    4
    2


    这一题是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
    ",c[i].num1);
    		}
    		printf("
    ");
    	}
    	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
    ",num1[i]);
    		}
    		printf("
    ");
    	}
    	return 0;
    }



  • 相关阅读:
    合并vector里的内容,输出一个string
    免费矢量图标下载【转载】
    NX二次开发-UFUN打开选择文件夹对话框UF_UI_create_filebox
    Windows路径操作API函数学习【转载】
    NX二次开发-UFUN设置对象线型UF_OBJ_set_font
    NX二次开发CreateDialog函数在UI.hxx文件和WinUser.h中的冲突【转载】
    NX二次开发-UFUN将工程图中的点坐标映射到建模绝对坐标UF_VIEW_map_drawing_to_model
    NX二次开发-UFUN将建模绝对空间中的点映射到工程图坐标UF_VIEW_map_model_to_drawing
    NX二次开发-UFUN CSYS坐标系转换UF_CSYS_map_point
    VC操作Excel之基本操作(颜色等)【转载】
  • 原文地址:https://www.cnblogs.com/herumw/p/9464702.html
Copyright © 2011-2022 走看看