1. 程式人生 > >codeforces DIV2 E. Garlands (離線、二維樹狀陣列)

codeforces DIV2 E. Garlands (離線、二維樹狀陣列)

題意:

給出你一個n*m矩陣,矩陣中有一些燈泡,這些燈泡連成了k條互不重疊的鏈。每個燈泡都有一定的權值w,但是隻有當燈泡開啟的時候,才會產生貢獻,剛開始所有的燈泡都是開著的。共有q次詢問,有兩種操作:
①“Switch i”——表示將編號為i的鏈所有的燈泡取反(即開變關,關變開)。
②“Ask x1,y1,x2,y2”——表示詢問以(x1,y1)和(x2,y2)為兩個端點的子矩形所產生的貢獻。

資料範圍:1 ≤ n, m, k ≤ 2000,1≤w≤ 10^9,q≤10^6,保證“Ask”的操作≤2000次
時限:3s

解題過程:

備註:翻閱了很多的題解,發現大多數的題解都是線上做的,雖然能夠過CF的評測,但是其實複雜度可以被卡到n^3*log(n)^2,自測資料很容易就可以卡掉。所以這裡介紹一種不會被卡的離線方法,複雜度為n^2*log(n)^2的,本機測驗極限資料能夠跑在3s之內。

下面進入正題。首先我們可以注意到題目中說到了Ask的次數不會超過兩千次,於是我們就可以從這裡入手。有點類似與線段樹lazy標記,我們可以對於每個“Switch”操作,我們並不一定每次都要改,而是進行記錄。因為我們可以發現,取反操作對於每個鏈做了偶數次之後,就相當於沒有做,所以我們只需要在每次Ask的時候,對所需要修改的鏈進行修改即可。然後我們考慮如何統計答案,既然詢問的是子矩陣的貢獻和,我們自然會想到字首和,但是這個子矩陣中包含著不同編號的鏈,而每條鏈在每次查詢的時候開關的狀態是不一樣的,所以我們就可以記ans陣列,ans[i][j]表示假設第i條鏈是開著的時候,對於第j個詢問的貢獻是多少,這個地方就可以用二位樹狀陣列進行維護,預處理的複雜度為n^2*log(n)^2。最後我們在遍歷每一個詢問,記change陣列,change[i]表示第i條鏈是否要進行修改,Ask的時候將開著的鏈貢獻新增進去,即為答案,總的複雜度問n^2*log(n)^2,只要常數不是非常的大,就是很容易過去的。

AC程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1
;} template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');} template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');} template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);} /*================Header Template==============*/ const int maxn=2005; int n,m,k,qcnt,q; ll T[maxn+50][maxn+50]; int len[maxn]; int x[maxn][maxn],y[maxn][maxn],w[maxn][maxn]; int c[1000005],qx1[maxn],qy1[maxn],qx2[maxn],qy2[maxn]; bool change[maxn]; ll ans[maxn][maxn]; #define lowbit(x) x&(-x) /*==================Define Area================*/ void Add(int x,int y,int w) { for(int i=x;i<=maxn;i+=lowbit(i)) { for(int j=y;j<=maxn;j+=lowbit(j)) { T[i][j]+=w; } } } ll Sum(int x,int y) { ll res=0; for(int i=x;i;i-=lowbit(i)) { for(int j=y;j;j-=lowbit(j)) { res+=T[i][j]; } } return res; } int main() { read(n);read(m);read(k); for(int i=1;i<=k;i++) { read(len[i]); for(int j=1;j<=len[i];j++) { read(x[i][j]);read(y[i][j]);read(w[i][j]); } } read(q); for(int i=1;i<=q;i++) { char opt[2]; scanf("%s",opt); if(opt[0]=='A') { ++qcnt; read(qx1[qcnt]);read(qy1[qcnt]);read(qx2[qcnt]);read(qy2[qcnt]); } else { read(c[i]); } } for(int i=1;i<=k;i++) { for(int j=1;j<=len[i];j++) { Add(x[i][j],y[i][j],w[i][j]); } for(int j=1;j<=qcnt;j++) { ans[i][j]=Sum(qx2[j],qy2[j])+Sum(qx1[j]-1,qy1[j]-1)-Sum(qx1[j]-1,qy2[j])-Sum(qx2[j],qy1[j]-1); } for(int j=1;j<=len[i];j++) { Add(x[i][j],y[i][j],-w[i][j]); } } for(int i=1,cnt=1;i<=q;i++) { if(c[i]) { change[c[i]]^=1; } else { ll res=0; for(int j=1;j<=k;j++) { if(!change[j]) res+=ans[j][cnt]; } printf("%lld\n",res); cnt++; } } return 0; }

相關推薦

codeforces DIV2 E. Garlands 離線陣列

題意: 給出你一個n*m矩陣,矩陣中有一些燈泡,這些燈泡連成了k條互不重疊的鏈。每個燈泡都有一定的權值w,但是隻有當燈泡開啟的時候,才會產生貢獻,剛開始所有的燈泡都是開著的。共有q次詢問,有兩種操作: ①“Switch i”——表示將編號為i的

【CF869E】The Untended Antiquity雜湊+陣列

當覆蓋兩點的最小矩形不同時,一定不可達 這樣的問題不難想到經典的二維樹狀陣列+差分來支援二維區間覆蓋+查詢 對於覆蓋操作 我們可以差分的給這個矩陣里加上一個編號 對於操牆操作 我們可以反著減去這個編號 對於查詢 就查詢這兩個點的值是否相同 編號的累積不影響 因為只有在同一個牆內才會累積 注意 如果只是單單的把

codeforces869EThe Untended Antiquity陣列

/* 二維樹狀陣列+Hash 題意: 給一個地圖(n,m) 三種操作: 1,在以(r1,c1)、(r2,c2)為對角的矩形四條邊上新增障礙 2,消除以(r1,c1)、(r2,c2)為對角的矩形四條邊上的障礙 3,判斷(r1,c1)到(r2,c2)是否存在一條路徑,不經過障礙 利用二維樹

2015年ACM/ICPC瀋陽賽區 I題陣列

題意:給你n(n<=1e5)個正整數二元組<a,b> (1<=a,b<=1e5) 給你m(m<=1e5)個正整數三元組<c,d,e>(1<=c,d<=1e3  1<=e<=1e5) 定義新

2018.10.23【校內模擬】行星通道計劃陣列

傳送門 解析: 我們發現,每一條線段會把原來的環狀分成兩段,兩條線段有交點當且僅當一條線段的起終點分別在另一條線段把環形分成的兩個部分中。 所以直接斷環成鏈,每次新加線段&lt;u,v&gt;&lt;u,v&gt;<u,v

NOIP模擬 行星通道計劃陣列

QAQ 【題目分析】 考慮樹狀陣列維護狀態,然後。。。。。就沒有然後了。。。。。沒想出來二維如何統計。 感覺正解很毒瘤啊,各種壓位操作。。。。所以正常打個二維樹狀陣列還是能過啊。。。。 考慮兩個連線點x,y,如果以後有兩個點x',y'經過他,那麼一定滿足x<x'

POJ2155 - Matrix 陣列

                                          &nb

See you~ hdu1892 陣列

Now I am leaving hust acm. In the past two and half years, I learned so many knowledge about Algorithm and Programming, and I met so many

poj 2155 Matrix陣列

樓教主出的二維樹狀陣列。 給出矩陣左上角和右下角座標,矩陣裡的元素 1變0 ,0 變1,然後給出詢問,問某個點是多少。 糾結好久了,一直沒什麼好思路,看discuss說四個角神馬的,我搜了下,理解了,樹狀數組裡記錄該點的變幻次數,或者直接%2也行。 查詢的時候Gets

POJ-2155陣列

學習了這篇部落格的講解徹底弄懂二維樹狀陣列,做了二維樹狀陣列的第1題。 雖然是二維,但跟一維的思想基本相同,只不過一維時用C[i]表示a[i-lowbit[i]+1] ~ a[i]的和,二維時用c[i][j]表示a[i-lowbit[i]+1][j-lowbit[j]+1

poj2155 Matrix經典陣列

吐槽:這題先說[x1,y1]和[x2,y2]是左上角和右下角的兩個點,又說x1<=x2&&y1<=y2,那就是x軸向右,y軸向下為正方向。mdzz啊,座標系這種東西能不能

高階陣列——區間修改區間查詢陣列

“高階”資料結構——樹狀陣列!※本文一切程式碼未經編譯,不保證正確性,如發現問題,歡迎指正!1. 單點修改 + 區間查詢最簡單的樹狀陣列就是這樣的:void add(int p, int x){ //給位置p增加x while(p <= n) sum[p] +=

數組進階 - 區間修改區間查詢OA信用盤平臺出租數組

沒有 信用 turn forum 修改 平臺出租 數字 現在 簡單 ①首先是最基礎OA信用盤平臺出租【話仙源碼論壇】hxforum.com【木瓜源碼論壇】papayabbs.com的樹狀數組: 復制代碼//BIT - 單點增加,區間查詢 - ststruct _BIT{in

Codeforces 341D Iahub and Xors (陣列 差分 推薦)

D. Iahub and Xors time limit per test 1 second memory limit per test 256 megabytes Iahub does not like background stories, so he'll tell you e

hdu 5517 三元組陣列

思路: 第一眼看還覺得沒法處理,但是我們可以發現他要求top三元組,所以對於二元組  a b 對於每個b 我只需要保留他的最大的a就可以了。生成的新的三元組最多就100000 個。 這樣的話,就直接  二維樹狀陣列求就可以了。 程式碼: #include<bit

陣列模板單點更新,區間求和以HDU 2642為例

題目:點選開啟連結 題意:輸入B後輸入座標,表示對應的點的燈變亮,輸入D後輸入座標表示對應的點燈滅,輸入Q後輸入一個矩形的左下角和右上角 輸出矩形內亮著的等的個數,注意燈亮過不能再亮,燈關了不能再關,所以用陣列標記,樹狀陣列模板中元素下標均從1開始,題目從0開始所以加1。

codeforces 869E. The Untended Antiquity(陣列,隨機化)

E. The Untended Antiquity time limit per test2 seconds memory limit per test512 megabytes inputstandard input outputstandard

POJ1195:Mobile phones 陣列 矩陣上點的區間和查詢更新均為

Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided int

牛客網暑期ACM多校訓練營第二場J.farm (隨機數+陣列)

題目連結 時間限制:C/C++ 4秒,其他語言8秒 空間限制:C/C++ 262144K,其他語言524288K 64bit IO Format: %lld 題目描述 White Rabbit has a rectangular farmland of n*m. In

POJ 2155 Matrix陣列+陣列陣列區間更新+單點查詢

Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[