• 【BZOJ 1176】【Balkan 2007】Mokia


    http://www.lydsy.com/JudgeOnline/problem.php?id=1176

    分治的例题

    把每个询问拆成四个询问,整体二分里x坐标递增,按x坐标扫的时候用树状数组维护y坐标前缀和。

    一开始想复杂了,按cdq分治先solve左边再处理中间再solve右边,这样每次都要对x坐标排序,常数巨大,T了好几次TwT

    后来参考了别人的代码,发现自己一开始就想复杂了。这道题不需要在solve完后还是保持原来的按x坐标递增的顺序,也不需要先处理出左边的信息才能更新右边的信息。

    这样直接分治啊~~~~~处理完一大块左边对右边的贡献再递归处理左右两块。只要一开始对x坐标排序即可,solve的过程从整到散,不需要再进行排序。

    一开始还忘了离散化,每次清空树状数组都用memsetヽ(*´Д`*)ノ后来发现从前往后扫一遍把原先加的减回去会快得多。

    时间复杂度$O(mlogmlogw)$,m的含义为所有修改和询问的数量,w的含义为离散化y坐标后的y坐标最大值,即树状数组的上界。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define lowbit(x) (x&(-x))
    using namespace std;
    int in() {
    	int k = 0, fh = 1; char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar())
    		if (c == '-') fh = -1;
    	for(; c >= '0' && c <= '9'; c = getchar())
    		k = (k << 3) + (k << 1) + c - '0';
    	return k * fh;
    }
    
    struct node {
    	int op, x, y, a, id, pos;
    	bool operator < (const node &A) const {
    		return x == A.x ? (y == A.y ? pos < A.pos : y < A.y) : x < A.x;
    	}
    } Q[200003], q[200003];
    
    int s, w, m = 0, ans[40003];
    
    namespace CDQ {
    	int bits[180003];
    	void update(int x, int num) {
    		for(; x <= w; x += lowbit(x)) bits[x] += num;
    	}
    	int Qsum(int x) {
    		int ret = 0;
    		for(; x; x -= lowbit(x)) ret += bits[x];
    		return ret;
    	}
    	
    	void solve(int l, int r) {
    		if (l == r) return;
    		int mid = (l + r) >> 1;
    		for(int i = l; i <= r; ++i) {
    			if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, Q[i].a);
    			if (Q[i].op == 2 && Q[i].id > mid) ans[Q[i].pos] += Q[i].a * Qsum(Q[i].y);
    		}
    		
    		for(int i = l; i <= r; ++i)
    			if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, -Q[i].a);
    		
    		int tl = l, tr = mid + 1;
    		for(int i = l; i <= r; ++i)
    			if (Q[i].id <= mid) q[tl++] = Q[i];
    			else q[tr++] = Q[i];
    		for(int i = l; i <= r; ++i) Q[i] = q[i];
    		
    		solve(l, mid);
    		solve(mid + 1, r);
    	}
    }
    
    int H[180003], cnt = 0, anscnt = 0;
    int main() {
    	s = in(); w = in(); int x1, y1, x2, y2;
    	for(int x = in(); x != 3; x = in())
    		if (x == 1) {
    			Q[++m].op = 1;
    			Q[m].x = in(); Q[m].y = in(); Q[m].a = in(); Q[m].id = m; Q[m].pos = 0;
    			H[++cnt] = Q[m].y;
    		} else {
    			x1 = in(); y1 = in(); x2 = in(); y2 = in();
    			H[++cnt] = y1 - 1; H[++cnt] = y2;
    			ans[++anscnt] = s * (x2 - x1 + 1) * (y2 - y1 + 1);
    			++m; Q[m] = (node) {2, x1 - 1, y1 - 1, 1, m, anscnt};
    			++m; Q[m] = (node) {2, x1 - 1, y2, -1, m, anscnt};
    			++m; Q[m] = (node) {2, x2, y1 - 1, -1, m, anscnt};
    			++m; Q[m] = (node) {2, x2, y2, 1, m, anscnt};
    		}
    	
    	sort(H + 1, H + cnt + 1);
    	cnt = unique(H + 1, H + cnt + 1) - H;
    	w = cnt - 1;
    	
    	for(int i = 1; i <= m; ++i)	Q[i].y = lower_bound(H + 1, H + cnt, Q[i].y) - H;
    	
    	sort(Q + 1, Q + m + 1);
    	
    	CDQ::solve(1, m);
    	
    	for(int i = 1; i <= anscnt; ++i) printf("%d
    ", ans[i]);
    	
    	return 0;
    }
    

    一定要想好了再码!

  • 相关阅读:
    [机器学习]单变量线性回归(最小二乘法)
    [机器学习]kNN进邻算法
    Python笔记(读取txt文件中的数据)
    [机器学习笔记] 1监督学习
    LeetCode(Add Two Numbers)
    缓冲区溢出在Linux虚拟机上的实现过程中的问题与解决
    数据库与后端的映射
    电子公文传输系统 团队作业(五):冲刺总结
    电子公文传输系统 团队作业(五):冲刺总结(第一天)
    电子公文传输系统 团队作业(四):描述设计
  • 原文地址:https://www.cnblogs.com/abclzr/p/5742795.html
Copyright © 2020-2023  润新知