zoukankan      html  css  js  c++  java
  • LG3801 红色的幻想乡 线段树+容斥原理

    问题描述

    经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。

    我们将幻想乡看做是一个 (n imes m) 的方格地区,一开始没有任何一个地区被红雾遮盖。蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区。如果两阵红雾碰撞,则会因为密度过大而沉降消失。灵梦察觉到了这次异变,决定去解决它。但在解决之前,灵梦想要了解一片范围红雾的密度。可以简述为两种操作:

    1 x y 蕾米莉亚站在坐标 ((x,y)) 的位置向四个方向释放无限长的红雾。

    2 x1 y1 x2 y2 询问左上点为 ((x1,y1)),右下点为 ((x2,y2)) 的矩形范围内,被红雾遮盖的地区的数量。


    题解

    认为站立的地方也是沉降。

    维护两棵线段树,一个维护行,一个维护列,单点修改,区间查询(树状数组也可以)

    (R,C) 分别代表行和列被覆盖数量,答案为 $ R imes (y2 - y1 + 1) + C imes (x2 - x1 + 1) - 2 imes R imes C $ 。

    减去两倍 (R imes C) 的原因:去掉行列统计各一次。


    (mathrm{Code})

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int maxn = 100000 + 7;
    const int maxm = 200000 + 7;
    
    int n, m, T;
    
    template < typename Tp >
    void read(Tp &x) {
    	x = 0;char ch = 1;int fh = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch=getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    void Init(void) {
    	read(n); read(m); read(T);
    }
    
    struct Segment_Tree {
    	#define lfc (x << 1)
    	#define rgc ((x << 1) | 1)
    	#define mid ((l + r) >> 1)
    	int val[maxn << 2];
    	void modify(int x, int l, int r, int pos) {
    		if(l == r) {
    			val[x] = 1 - val[x];
    			return ;
    		}
    		if(pos <= mid) modify(lfc, l, mid, pos);
    		else modify(rgc, mid + 1, r, pos);
    		val[x] = val[lfc] + val[rgc];
    	}
    	int query(int x, int l, int r, int L, int R) {
    		if(L <= l && r <= R) return val[x];
    		if(r < L || l > R) return 0;
    		return query(lfc, l, mid, L, R) + query(rgc, mid + 1, r, L, R);
    	}
    }row, column;
    
    
    void operator1(void) {
    	int x, y;
    	read(x); read(y);
    	row.modify(1, 1, n, x);
    	column.modify(1, 1, m, y);
    }
    
    void operator2(void) {
    	int x1, x2, y1, y2;
    	read(x1); read(y1); read(x2); read(y2);
    	int R = row.query(1, 1, n, x1, x2), C = column.query(1, 1, m, y1, y2);
    	LL ans = (LL)(y2 - y1 + 1) * (LL)R + (x2 - x1 + 1) *(LL)C - (LL)R * (LL)C * 2ll;
    	printf("%lld
    ", ans);
    }
    
    void Work(void) {
    	while(T--) {
    		int op; read(op);
    		if(op == 1) operator1();
    		else operator2();
    	}
    }
    
    int main(void) {
    	Init();
    	Work();
    	return 0;
    }
    
  • 相关阅读:
    学期总结
    Sprint 2(第一天)
    学期总结
    实验四、主存空间的分配和回收
    阅读《构建之法》与链接有感.
    《构建之法》八、九、十章读后感
    Scrum领取任务
    实验三、进程调度模拟程序实验
    《构建之法》6-7章读后感
    实验二 作业调度模拟程序
  • 原文地址:https://www.cnblogs.com/liubainian/p/12571638.html
Copyright © 2011-2022 走看看