zoukankan      html  css  js  c++  java
  • 【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;
    }
    

    一定要想好了再码!

  • 相关阅读:
    (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
    HTTP KeepAlive模式
    Windows 7 中的 God Mode
    我的开发环境配置经验
    C#格式化数值结果表(格式化字符串)
    我可怜的笔记本电脑
    JetBrains ReSharper 5.x 注册机
    异常处理准则
    调用 Windows 7 中英文混合朗读
    oracle笔记(2010130)
  • 原文地址:https://www.cnblogs.com/abclzr/p/5742795.html
Copyright © 2011-2022 走看看