1. 程式人生 > >[BZOJ2877][Noi2012]魔幻棋盤(差分+二維線段樹)

[BZOJ2877][Noi2012]魔幻棋盤(差分+二維線段樹)

Address

Solution

調了一整個下午 發現每次詢問的矩形一定包含 (X,Y)(X,Y) ,所以我們自然地想到把棋盤拆成 44 個部分,分別為 (X,Y)(X,Y) 的左上部分(橫座標小於等於 XX 且縱座標小於等於 YY ),右上部分(橫座標小於等於 XX 且縱座標大於等於 YY ),左下部分,右下部分。修改則可以在每個部分進行修改一次(如果修改操作的子矩形與這個部分有交集) 這樣就相當於支援矩形加,求二維字首 gcd\gcd 。 先考慮如果這是一個序列,支援區間加和求字首 gcd\gcd 。 眾所周知,處理區間加有一種很好的方法,那就是通過差分把區間修改轉成單點修改。 設這個序列是 a

a ,這個序列的差分為 bb ,那麼 [1,x][1,x]gcd\gcd 為: gcdi=1xj=1ibj\gcd_{i=1}^x\sum_{j=1}^ib_j gcd\gcd 有一個性質: gcd(a,b)=gcd(a,a+b)\gcd(a,b)=\gcd(a,a+b) 。 於是上式實際上可以轉成: gcdi=1xbi\gcd_{i=1}^xb_i 用線段樹就能輕鬆維護。 而一個矩形的二維差分定義為: bi,j=ai,jai1,jai,j1+ai
1,j1b_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}
用二維線段樹維護 gcdb\gcd b 即可。 複雜度 O((NM+T)logNlogM)O((NM+T)\log N\log M)

Code

這應該是到現在寫過最長的程式碼了

#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream> #include <algorithm> #define For(i, a, b) for (i = a; i <= b; i++) #define p2 p << 1 #define p3 p << 1 | 1 using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef long long ll; inline ll readll() { ll res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } template <class Orz> Orz Max(Orz a, Orz b) {return a > b ? a : b;} template <class Orz> Orz Min(Orz a, Orz b) {return a < b ? a : b;} const int N = 5e5 + 5, M = N << 2, L = 3e7 + 5; int n, m, X, Y, q, rt[4][M], ToT; struct node { int lc, rc; ll xgcd; } T[L]; vector<ll> a[N]; void modify(int l, int r, int pos, ll x, int &p) { if (!p) p = ++ToT; if (l == r) return (void) (T[p].xgcd += x); int mid = l + r >> 1; if (pos <= mid) modify(l, mid, pos, x, T[p].lc); else modify(mid + 1, r, pos, x, T[p].rc); T[p].xgcd = __gcd(T[T[p].lc].xgcd, T[T[p].rc].xgcd); } void upt(int l, int r, int k, int &p, int lp, int rp) { if (!p) p = ++ToT; T[p].xgcd = __gcd(T[lp].xgcd, T[rp].xgcd); if (l == r) return; int mid = l + r >> 1; if (k <= mid) upt(l, mid, k, T[p].lc, T[lp].lc, T[rp].lc); else upt(mid + 1, r, k, T[p].rc, T[lp].rc, T[rp].rc); } void change(int l, int r, int id, int x, int y, ll v, int p) { if (l == r) { if (id & 1) modify(Y, m, y, v, rt[id][p]); else modify(1, Y, y, v, rt[id][p]); return; } int mid = l + r >> 1; if (x <= mid) change(l, mid, id, x, y, v, p2); else change(mid + 1, r, id, x, y, v, p3); if (id & 1) upt(Y, m, y, rt[id][p], rt[id][p2], rt[id][p3]); else upt(1, Y, y, rt[id][p], rt[id][p2], rt[id][p3]); } ll query(int l, int r, int s, int e, int p) { if (!p) return 0; if (l == s && r == e) return T[p].xgcd; int mid = l + r >> 1; if (e <= mid) return query(l, mid, s, e, T[p].lc); else if (s >= mid + 1) return query(mid + 1, r, s, e, T[p].rc); else return __gcd(query(l, mid, s, mid, T[p].lc), query(mid + 1, r, mid + 1, e, T[p].rc)); } ll ask(int l, int r, int id, int lx, int rx, int ly, int ry, int p) { if (l == lx && r == rx) return id & 1 ? query(Y, m, ly, ry, rt[id][p]) : query(1, Y, ly, ry, rt[id][p]); int mid = l + r >> 1; if (rx <= mid) return ask(l, mid, id, lx, rx, ly, ry, p2); else if (lx >= mid + 1) return ask(mid + 1, r, id, lx, rx, ly, ry, p3); else return __gcd(ask(l, mid, id, lx, mid, ly, ry, p2), ask(mid + 1, r, id, mid + 1, rx, ly, ry, p3)); } void submat(int lx, int ly, int rx, int ry, int id, ll delta) { int _lx, _ly, _rx, _ry; if (id == 0) _lx = 1, _ly = 1, _rx = X, _ry = Y; else if (id == 1) _lx = 1, _ly = Y, _rx = X, _ry = m; else if (id == 2) _lx = X, _ly = 1, _rx = n, _ry = Y; else _lx = X, _ly = Y, _rx = n, _ry = m; if (rx < _lx || _rx < lx || ry < _ly || _ry < ly) return; lx = Max(lx, _lx); ly = Max(ly, _ly); rx = Min(rx, _rx); ry = Min(ry, _ry); if (id == 0) { change(1, X, 0, rx, ry, delta, 1); if (lx > 1) change(1, X, 0, lx - 1, ry, -delta, 1); if (ly > 1) change(1, X, 0, rx, ly - 1, -delta, 1); if (lx > 1 && ly > 1) change(1, X, 0, lx - 1, ly - 1, delta, 1); } else if (id == 1) { change(1, X, 1, rx, ly, delta, 1); if (lx > 1) change(1, X, 1, lx - 1, ly, -delta, 1); if (ry < m) change(1, X, 1, rx, ry + 1, -delta, 1); if (lx > 1 && ry < m) change(1, X, 1, lx - 1, ry + 1, delta, 1); } else if (id == 2) { change(X, n, 2, lx, ry, delta, 1); if (rx < n) change(X, n, 2, rx + 1, ry, -delta, 1);

相關推薦

[BZOJ2877][Noi2012]魔幻棋盤+線段

Address Solution 調了一整個下午 發現每次詢問的矩形一定包含 (X,Y)(X,Y)(X,Y) ,所以我們自然地想到把棋盤拆成 444 個部分,分別為 (X,Y)(X,Y)(X,Y) 的左上部分(橫座標小於等於 XXX 且縱座標小於等於 YYY

洛谷1083+二分 or 線段

urn spa min while 線段 turn 通過 return int 第一種方法:可以二分最大天數訂單的答案然後通過差分求一下是否可行。 1 const int maxn = 1e6 + 5; 2 int n, m, a[maxn], ans; 3

【BZOJ4785】[Zjoi2017]狀數組 線段

這也 現在 ont 平面 nbsp -s mil 比賽 turn 【BZOJ4785】[Zjoi2017]樹狀數組 Description 漆黑的晚上,九條可憐躺在床上輾轉反側。難以入眠的她想起了若幹年前她的一次悲慘的OI 比賽經歷。那是一道基礎的樹狀數組題。給出

BZOJ4785 ZJOI2017狀數組概率+線段

cal cor += clas str col else 個數 clu   可以發現這個寫掛的樹狀數組求的是後綴和。find(r)-find(l-1)在模2意義下實際上查詢的是l-1~r-1的和,而本來要查詢的是l~r的和。也就是說,若結果正確,則a[l-1]=a[r](m

簡單的字串迴文子集數+線段

題目: 思路:第一步先處理如何計算一個區間的迴文子集個數 構成迴文串,有兩種情況: 1. 每種字母都選偶數個,這樣一定可以構成迴文串                     &nbs

bzoj1513 Tet-Tetris 3D線段

時間限制:1秒 記憶體限制:64M 【問題描述】   Tetris 3D “Tetris” 遊戲的作者決定做一個新的遊戲, 一個三維的版本。 在裡面很多立方體落在平面板,一個立方體開始落下直到碰上一個以前落下的立方體或者落地即停止。作者想改變一下游戲

HDU 1832 Luck and Love 線段

Problem Description 世界上上最遠的距離不是相隔天涯海角 而是我在你面前 可你卻不知道我愛你                 ―― 張小嫻 前段日子,楓冰葉子給Wiskey做了個徵婚啟事,聘禮達到500萬哦,天哪,可是天文數字了啊,不知多少MM蜂擁而至,頓

POJ 1201約束+最長路

題意:一個整數集合Z有n個區間,每個區間有3個值,ai,bi,ci代表,在區間[ai,bi]上至少有ci個整數屬於集合Z,ci可以在區間內任意取不重複的點。現在要滿足所有區間的約束條件,問最少可選多少個點。 思路:首先得了解何為差分約束,https://blog.csdn.

【洛谷3275】[SCOI2011] 糖果約束系統入門題

點此看題面 大致題意: 有\(N\)個小朋友,要求每個人都得到糖果,且每個人的糖果總數滿足一定的關係式,請你求出至少共分給小朋友們多少糖果。 關係式的轉換 首先,我們可以將題目中給定的式子進行轉換: \(A=B\):這個式子可以拆成\(A≥B\)和\(B≥A\),再轉換一下就變成了\(A-B

poj 3159 Candies 約束系統裸題

Time Limit: 1500MS Memory Limit: 131072K Total Submissions: 31698 Accepted: 8837 Description During the kindergarten

小a的轟炸遊戲,前綴和

== click art fine details display type -- isp 題目傳送門 題意: 給出一個n*m的矩形,然後有兩個操作. 1操作,對一個給出的菱形,對菱形範圍內的東西進行+1。 2操作,對一個上半菱形的區域,進行+1操作。 最後求矩形

51Nod1085 0-1揹包一維和陣列實現

揹包是典型的動態規劃問題,關於揹包問題的詳解,推薦部落格:點選開啟連結(這篇部落格有點錯誤,程式碼for迴圈裡錯了,不過講解 的很詳細) 題目如下: 在N件物品取出若干件放在容量為W的揹包裡,每件物品的體積為W1,W2……Wn(Wi為整數),與之相對應的價值為P1,P2……Pn(Pi為整數)

Opencv+Zbar碼識別標準條形碼/碼識別

使用Opencv+Zbar組合可以很容易的識別圖片中的二維碼,特別是標準的二維碼,這裡標準指的是二維碼成像清晰,圖片中二維碼的空間佔比在40%~100%之間,這樣標準的圖片,Zbar識別起來很容易,不需要Opencv額外的處理。 下邊這個例程演示兩者配合對條形碼和二維碼的

LeetCode | Validate Binary Search Tree有效的叉搜尋

Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a no

98. Validate Binary Search Tree判斷合法叉搜尋

Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of

【BZOJ4785】狀陣列ZJOI2017-概率+線段+動態開點

測試地址:樹狀陣列 做法:本題需要用到概率+二維線段樹+動態開點。 首先分析題目,對樹狀陣列結構熟悉的同學(不熟悉的話…畫一畫或者打個表也行)就能看出,題目中的資料結構求的是字尾和。那麼當我們詢問[l,r][l,r]時,我們原來是算[1,l−1]xor[1,

POJ 2019 Cornfields 線段的初始化與最值查詢

popu def comm init 都沒有 data- ont emp class 模板到不行。。連更新都沒有。。。存個模板。 理解留到小結的時候再寫。 #include <algorithm> #include <iostream>

Codeforces 242E. XOR on Segment (線段 lazy操作 xor)

又是 維護 problem -- spa c++ push_back str 題目 題目鏈接: http://codeforces.com/problemset/problem/242/E 題意: 給出一個序列,有兩種操作,一種是計算l到r的和,另一種是讓l到r的數全部和x

UVa 11297 Census (線段)

cpp [0 ons 上一個 highlight ctype comm bitset space 題意:給定上一個二維矩陣,有兩種操作 第一種是修改 c x y val 把(x, y) 改成 val 第二種是查詢 q x1 y1 x2 y2 查詢這個矩形內的最大值和最小值。

BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 狀數組套線段/線段(MLE) 動態開點)4

ini esp mes http mar cnblogs static gpo max 題目鏈接:BZOJ 洛谷 \(O(n^2)\)DP很好寫,對於當前的i從之前滿足條件的j中選一個最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++