• 线段树+扫描线+离散化


    题意

    T组数据,每次给你n个点,含点权

    给你一个矩形,只能底边平行x轴放置

    求矩形内点权和的最大值

    T≤10,n≤1e5

    分析

    首先,看到n和xy的范围,想到离散化
    其次, 我们求的是一个框框(范围)内的东西, 特别是有扫描线,且能够出入,所以想到线段树
    (有点牵强...主要是因为我们做的就是线段树题目...
    想想怎么实现,怎么做题
    因为是一个框框,它框住某点的位置有多个,这样不好维护线段树,所以
    我们把每个点(i,j)作为左下角,向右向上延生至(i+w-1,j+h-1),这个矩形加上(i,j)的贡献(即亮度 )(注:不包括边框)
    不考虑横坐标,它能影响到的矩形为:y到y+h的点所代表的所有矩形。
    考虑上横坐标,用扫描线,及时删除不在当前横坐标能覆盖的星星。

    参考代码&分析

    https://www.luogu.org/blog/HotoChino/solution-p1502

    错误代码(留坑代填(wtm做了一下午....还是没有找到错误

    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    #define MAX 10000+9
    
    int n,w,h;
    int mx[MAX<<3], day[MAX<<1], addv[MAX<<2];//Discrete Array y 离散化y数组 
    //线段树四倍,扫描线两倍 
    struct seg{//平行于y轴的扫描线 
    	int x, y1, y2, l;
    	seg(int x=0, int y1=0, int y2=0, int l=0) : x(x), y1(y1), y2(y2), l(l) {} 
    	bool operator < (const seg& xxx) const {
    		return x < xxx.x;//从左向右, 按顺序扫, 所以需要排序 
    	}
    } s[MAX<<1];
    struct node{
    	int x, y, l;
    	bool operator < (const node& xxx) const {
    		return x < xxx.x ;
    	}
    }a[MAX];
    
    void push_up(int o) { mx[o] = max(mx[o<<1], mx[o<<1|1]); }
    void pushtag(int o, int l, int r, int v) { addv[o] += v, mx[o] += v;};
    void push_down(int o, int l, int r) {
    	if(addv[o] == 0) return ;
    	addv[o<<1] += addv[o];
    	mx[o<<1] += addv[o];
    	addv[o<<1|1] += addv[o];
    	mx[o<<1|1] += addv[o];
    	addv[o] = 0;
    }
    void optdate(int o, int l, int r, int ql, int qr, int v) {
    	if(ql <= l && r <= qr) { pushtag(o, l, r, v); return ;}
    	push_down(o, l, r);
    	int mid = (l+r)>>1;
    	if(ql <= mid) optdate(o<<1, l, mid, ql, qr, v);
    	if(qr > mid) optdate(o<<1|1, mid+1, r, ql, qr, v);
    	push_up(o);
    }
    
    int main() {
    	int T;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d%d", &n, &w, &h);
    		memset(mx, 0, sizeof(mx));
    		memset(day, 0, sizeof(day));
    		int x,y,l;
    		for(int i = 1; i <= n; i++) {
    			scanf("%d%d%d",&x,&y,&l);//亮度l 
    			s[i] = seg(x, y, y+h-1, l);
    			day[i] = y;
    			s[i+n] = seg(x+w-1, y, y+h-1, -l);//-l表示出 
    			day[i+n] = y+h-1;
    		}
    		n <<= 1;//两倍 
    		sort(day+1, day+1+n);
    		int tot = 1;
    		for(int i = 2; i <= n; i++) if(day[i] != day[tot]) day[++tot] = day[i];
    		/*unique的使用: 
    		sort(day+1,day+1+n);//排序 
            int tot=unique(day+1,day+1+n)-day-1;//去重 */
            sort(s+1,s+1+n);//根据横坐标排序 
    		//build();刚开始就是空的 
    		int ans = 0;
    		for(int i = 1; i <= n; i++) {
    			int l = lower_bound(day+1, day+1+tot, s[i].y1 ) - day;//二分查找边界 
    			int r = lower_bound(day+1, day+1+tot, s[i].y2 ) - day;//找到y1和y2,求出区间最大值 
    			if(l > r) swap(l, r);
    			optdate(1, 1, tot, l, r, s[i].l );//下次再扫到右边界时就会在原区间加上-l,即删除; //
    			ans = max(ans, mx[1]);
    		}
    		printf("%d
    ",ans);
    	}
    	
    }
    
  • 相关阅读:
    webpack初识
    Vue+ElementUi项目实现表格-单行拖拽
    promise/async与await 的执行顺序梳理
    MDN社区
    angularjs中的异步操作
    javascript中的字符串和数组的互转
    angularjs的练习题
    angularjs基础知识
    开发的两种方式
    ASP.NET中的HttpClient发送请求
  • 原文地址:https://www.cnblogs.com/tyner/p/11251690.html
Copyright © 2020-2023  润新知