洛谷 P2184 贪婪大陆 解题报告
P2184 貪婪大陸
題目背景
面對螞蟻們的瘋狂進攻,小\(FF\)的\(Tower\) \(defence\)宣告失敗……人類被螞蟻們逼到了\(Greed\) \(Island\)上的一個海灣。現在,小\(FF\)的后方是一望無際的大海, 前方是變異了的超級螞蟻。 小\(FF\)還有大好前程,他可不想命喪于此, 于是他派遣手下最后一批改造\(SCV\)布置地雷以阻擋螞蟻們的進攻。
題目描述
小\(FF\)最后一道防線是一條長度為\(N\)的戰壕, 小\(FF\)擁有無數多種地雷,而SCV每次可以在\([L,R]\)區間埋放同一種不同于之前已經埋放的地雷。 由于情況已經十萬火急,小\(FF\)在某些時候可能會詢問你在\([L',R']\)區間內有多少種不同的地雷, 他希望你能盡快的給予答復。
輸入輸出格式
輸入格式:
第一行為兩個整數\(n\)和\(m\); \(n\)表示防線長度,\(m\)表示\(SCV\)布雷次數及小\(FF\)詢問的次數總和。
接下來有\(m\)行, 每行三個整數\(Q\),\(L\),\(R\); 若\(Q\)=1則表示\(SCV\)在\([L,R]\)這段區間布上一種地雷, 若\(Q=2\)則表示小\(FF\)詢問當前\([L,R]\)區間總共有多少種地雷。
輸出格式:
對于小FF的每次詢問,輸出一個答案(單獨一行),表示當前區間地雷總數。
說明:
對于30%的數據: \(0<=n, m<=1000\);
對于100%的數據:\(0<=n, m<=10^5\).
說兩個方法吧
方法一:維護區間和和合并區間時多加上的一部分,基于容斥原理,是這位大佬想到的
具體的:
我們維護\(sum\)代表這個區間的種類數,每次區間修改操作即為對二進制所劃分的每個區間+1(不是對每個值,是對區間),防止退化我們用一個\(lazy1\)維護
這時候在區間合并的時候就會產生問題,會重復統計。
我們再維護一個值\(mer\)代表這個二進制區間被多少次劃分時分開了,則統計答案時即為\(sum[ls]+sum[rs]-mer[ls]\)
這個也是區間操作,同樣用一個\(lazy2\)來維護
Code:
#include <cstdio> #define ls id<<1 #define rs id<<1|1 const int N=100010; int sum[N<<2],mer[N<<2],lazy1[N<<2],lazy2[N<<2],n,m; void push_down(int id,int l,int r) {if(l!=r){sum[ls]+=lazy1[id];sum[rs]+=lazy1[id];mer[ls]+=lazy2[id];lazy1[ls]+=lazy1[id];lazy1[rs]+=lazy1[id];lazy2[ls]+=lazy2[id];lazy2[rs]+=lazy2[id];}lazy1[id]=lazy2[id]=0; } void change(int id,int l,int r,int L,int R) {if(l==L&&r==R){sum[id]++;lazy1[id]++;lazy2[id]++;return;}int Mid=L+R>>1;if(r<=Mid)change(ls,l,r,L,Mid);else if(l>Mid)change(rs,l,r,Mid+1,r);else{mer[ls]++;change(ls,l,Mid,L,Mid);change(rs,Mid+1,r,Mid+1,R);}push_down(id,L,R);sum[id]=sum[ls]+sum[rs]-mer[ls]; } int query(int id,int l,int r,int L,int R) {push_down(id,L,R);if(l==L&&r==R)return sum[id];int Mid=L+R>>1;if(r<=Mid)return query(ls,l,r,L,Mid);else if(l>Mid)return query(rs,l,r,Mid+1,r);elsereturn query(ls,l,Mid,L,Mid)+query(rs,Mid+1,r,Mid+1,R)-mer[ls]; } int main() {scanf("%d%d",&n,&m);int q,l,r;for(int i=1;i<=m;i++){scanf("%d%d%d",&q,&l,&r);if(q==1) change(1,l,r,1,n);else printf("%d\n",query(1,l,r,1,n));}return 0; }方法二:維護區間兩端進行統計
我們發現,對于一個區間\(1\)~\(i\),\(i\)及其左邊的區間的左端點的數量即為答案
對于一個區間\(i\)~\(n\),\(i\)左邊的右端點不是它的答案
綜合一下,對于一個區間\(l\)~\(r\),\(r\)及左邊的左端點數量-\(l\)左邊的右端點數量,不就是\(l\)~\(r\)所覆蓋的區間數量了嗎?
單點修改,我們只需要用兩個樹狀數組維護就行了
Code:
#include <cstdio> const int N=100010; int s[2][N],n,m; int query(int typ,int x) {int sum=0;while(x){sum+=s[typ][x];x-=x&-x;}return sum; } void add(int typ,int x) {while(x<=n){s[typ][x]+=1;x+=x&-x;} } int main() {scanf("%d%d",&n,&m);int q,l,r;for(int i=1;i<=m;i++){scanf("%d%d%d",&q,&l,&r);if(q==1)add(0,l),add(1,r);elseprintf("%d\n",query(0,r)-query(1,l-1));}return 0; }2018.7.12
轉載于:https://www.cnblogs.com/butterflydew/p/9299948.html
總結
以上是生活随笔為你收集整理的洛谷 P2184 贪婪大陆 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用JS实现简单的瀑布流效果
- 下一篇: 在基于nuxt的移动端页面中引用mint