給乙個初始值都是0的0-1矩陣,兩個操作:1.選擇乙個點,將其所在排和列(不包括該點)的數字取反。2.求乙個子矩形內的數字和。n,m,q<=100000.
n,m<=100000,每個x線段樹都維護乙個有400000個節點的y線段樹,而x節點也要400000個,空間受不了。
如果我們要更新一排,x線段樹沒有達到「排除一半」的功能,必須遍歷到所有x、y節點,時間受不了。
與後者等價的,是把整個矩陣的其它數字都取反,而不僅僅是其所在排列的。
不要被「不包括該點」迷惑。翻轉不包括該點,相當於先翻轉該點所在排,再翻轉所在列,該點翻轉了兩次,數字仍然不變。
這樣,我們就可以從對排和對列單獨分析作為思路了。我們可以對於各排和各列定義乙個0-1狀態表示如果不存在交叉點,則該排上的所有數字是1還是0。定義一排(列)的狀態為1,且經過乙個矩形,則該排(列)穿過該矩形。這樣,我們要查詢的子矩形內的數字和就等於穿過該矩形的排數*該矩形佔的列數+穿過該矩形的列數*該矩形佔的排數-交叉點個數*2(其=穿過該矩形的排數*穿過該矩形的列數)。穿過矩形的排數、列數可以分別對排、列維護乙個單點修改,區間查詢的線段樹表示區間[l,r]內狀態為1的點的個數是多少。
#include #include #include #include using namespace std;#define ll long long
const int max_node = 100010 * 4;
struct rangetree
int mid = (l + r) / 2;
if(p <= mid)
update(cur * 2, l, mid, p);
if(p > mid)
update(cur * 2 + 1, mid + 1, r, p);
sum[cur] = sum[cur * 2] + sum[cur * 2 + 1];
}ll query(int cur, int sl, int sr, int al, int ar)
public:
rangetree(int n):n(n){}
void update(int p)
ll query(int l, int r)
};int main()
}return 0;
}
luogu P3801 紅色的幻想鄉
嘟嘟嘟 首先人人都能想到是線段樹,不過二維線段樹肯定會mle tle的。我們換一種想法,不去修改整個區間,而是修改乙個點 開橫豎兩個線段樹,分別記錄哪些行和列被修改了。因為如果兩陣紅霧碰撞,則會因為密度過大而沉降消失,所以自然想到亦或。統計的時候求出這個矩形內有哪些行和列被修改了,接著把這些行和列的...
紅色的幻想鄉 洛谷p3801
蕾公尺莉亞的紅霧異變失敗後,很不甘心。經過上次失敗後,蕾公尺莉亞決定再次發動紅霧異變,但為了防止被靈夢退治,她決定將紅霧以奇怪的陣勢釋放。我們將幻想鄉看做是乙個n m的方格地區,一開始沒有任何乙個地區被紅霧遮蓋。蕾公尺莉亞每次站在某乙個地區上,向東南西北四個方向各發出一條無限長的紅霧,可以影響到整行...
洛谷 P3801 紅色的幻想鄉
蕾公尺莉亞的紅霧異變失敗後,很不甘心。經過上次失敗後,蕾公尺莉亞決定再次發動紅霧異變,但為了防止被靈夢退治,她決定將紅霧以奇怪的陣勢釋放。我們將幻想鄉看做是乙個n m的方格地區,一開始沒有任何乙個地區被紅霧遮蓋。蕾公尺莉亞每次站在某乙個地區上,向東南西北四個方向各發出一條無限長的紅霧,可以影響到整行...