AtCoder Regular Contest 085 F NRE 線段樹優化dp
題意
有長度為n初始全為0的陣列A和僅由0和1組成的陣列B。現在給出m個區間,每次可以選擇某個區間[l,r],使得A陣列下標在[l,r]之間的元素變為1。問A和B最小不同位置數量是多少。
n,m<=200000
分析
比賽的時候看成是區間取反,就以為這是道不可做題。
這題的題解用了比較巧妙的轉化方式。把(ai,bi)看成是一個數對,那麼答案其實就是(1,0)和(0,1)的數量,也就相當於(0,1)+(@,0)-(0,0)的最小值,其中@表示可以取任意值。注意到(@,0)的數量是固定的,那麼要求的實際就是(0,1)-(0,0)的最小值,也就是說,1的沒有貢獻的。
然後就可以大力dp了。
設f[i,j]表示前i個數已經確定,且當前的最後一個1在位置j時的最小代價。
我們可以列舉以i為起點的區間,設為[i,r]
那麼有f[i,r]=min(f[i-1,k]+w[k+1,i-1])。其中若l>r則w[l,r]=0,反之則w[l,r]為b[l,r]中1的數量-0的數量。
用線段樹優化即可。
程式碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=200005;
const int inf=1000000000;
int n,m,s1[N],s0[N];
struct tree{int mn,tag;}t[N*5];
vector<int> vec[N];
pair<int ,int> a[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void pushdown(int d,int l,int r)
{
if (!t[d].tag||l==r) return;
int w=t[d].tag;t[d].tag=0 ;
t[d*2].tag+=w;t[d*2+1].tag+=w;
t[d*2].mn+=w;t[d*2+1].mn+=w;
}
void ins(int d,int l,int r,int x,int y)
{
pushdown(d,l,r);
if (l==r) {t[d].mn=min(t[d].mn,y);return;}
int mid=(l+r)/2;
if (x<=mid) ins(d*2,l,mid,x,y);
else ins(d*2+1,mid+1,r,x,y);
t[d].mn=min(t[d*2].mn,t[d*2+1].mn);
}
void modify(int d,int l,int r,int x,int y,int z)
{
if (x>y) return;
pushdown(d,l,r);
if (l==x&&r==y) {t[d].tag+=z;t[d].mn+=z;return;}
int mid=(l+r)/2;
modify(d*2,l,mid,x,min(y,mid),z);
modify(d*2+1,mid+1,r,max(x,mid+1),y,z);
t[d].mn=min(t[d*2].mn,t[d*2+1].mn);
}
int query(int d,int l,int r,int x,int y)
{
if (x>y) return inf;
pushdown(d,l,r);
if (l==x&&r==y) return t[d].mn;
int mid=(l+r)/2;
return min(query(d*2,l,mid,x,min(y,mid)),query(d*2+1,mid+1,r,max(x,mid+1),y));
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
s0[i]=s0[i-1];s1[i]=s1[i-1];
int x=read();
if (!x) s0[i]++;
else s1[i]++;
}
m=read();
for (int i=1;i<=m;i++) a[i].first=read(),a[i].second=read();
sort(a+1,a+m+1);
for (int i=1;i<=m;i++) vec[a[i].first].push_back(a[i].second);
for (int i=1;i<=n*4+4;i++) t[i].mn=inf;
ins(1,0,n,0,0);
for (int i=1;i<=n;i++)
{
for (int j=0;j<vec[i].size();j++) ins(1,0,n,vec[i][j],query(1,0,n,0,vec[i][j]));
if (s1[i]-s1[i-1]) modify(1,0,n,0,i-1,1);
else modify(1,0,n,0,i-1,-1);
}
printf("%d",query(1,0,n,0,n)+s0[n]);
return 0;
}
相關推薦
AtCoder Regular Contest 085 F NRE 線段樹優化dp
題意 有長度為n初始全為0的陣列A和僅由0和1組成的陣列B。現在給出m個區間,每次可以選擇某個區間[l,r],使得A陣列下標在[l,r]之間的元素變為1。問A和B最小不同位置數量是多少。 n,m<=200000 分析 比賽的時候看成是區間取反,
AtCoder Regular Contest 075 E - Meaningful Mean 樹狀數組求順序對, 前綴和
n) cin 答案 bound std lan memset main ani 題目鏈接: http://arc075.contest.atcoder.jp/tasks/arc075_c 題意: 給你一個序列和一個數k,求有多少對l,r,使得a[l]+a[l+1]+...+
AtCoder Regular Contest 081 F - Flip and Rectangles
題目傳送門:https://arc081.contest.atcoder.jp/tasks/arc081_d 題目大意: 給定一個\(n×m\)的棋盤,棋盤上有一些黑點和白點,每次你可以選擇一行或一列,將上面所有的顏色取反,問若干次操作後可以得到的最大全黑子矩陣面積 首先我們可以發現,對於一個\(2×2
AtCoder Regular Contest 079 F
題意 給出一棵外向環套樹,問能否給每一個點定一個權值,使得每個點的權值都滿足其恰好是該點所有後繼節點的mex。 n<=200000 分析 對於不在環上的節點,它的權值是唯一確定的。對於環上的任意一個點,它的權值有兩種可能,一種是它的所有非環上後
降臨(線段樹優化dp)
main spa space odi pri line 除了 發現 獲得 降臨 選定點i會有代價\(c_i\),如果一個區間j內的點全被選擇,就可以獲得回報\(p_j\)。點數和區間個數\(<1e5\)。 還以為是線段樹優化網絡流(50萬個點200萬條邊看上去很可
題解:CF115E(線段樹優化dp)
定義 可能 bit tput space nbsp sans odi bsp 題目描述 你是一個賽車比賽的組織者,想在線性王國中安排一些比賽。 線性王國有n條連續的從左到右的道路。道路從左到右依次編號為從1到n,因此道路按照升序排列。在這些道路上可能會有幾場比賽,每一場
CF-833B The Bakery(線段樹優化Dp)
imu ger another art 區間 produce let span start Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought r
luogu2605 基站選址 (線段樹優化dp)
設f[i][j]表示在第i個村莊建第j個基站的花費 那麼有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中間的不能被滿足的村莊的賠償金之和 如果把每個村莊能被滿足的區間處理出來,記做$[l_i,r_i]$,那麼i,j不能滿足的村莊,就是$i&
【題解】poj3171 Cleaning Shifts 線段樹優化DP
題目連結 Description Farmer John’s cows, pampered since birth, have reached new heights of fastidiousness. They now require their barn
BZOJ1835: [ZJOI2010]base 基站選址(線段樹優化Dp)
Description 有N個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為Di。需要在這些村莊中建立不超過K個通訊基站,在第i個村莊建立基站的費用為Ci。如果在距離第i個村莊不超過Si的範圍內建立了一個通訊基站,那麼就成它被覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,
[ZJOI2010]基站選址(線段樹優化dp)
坑待填。 \(Code\ Below:\) #include <bits/stdc++.h> #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; const int maxn=20000+10
BZOJ 3790 神奇項鍊(迴文自動機+線段樹優化DP)
我們預處理出來以i為結尾的最長迴文字尾(迴文自動機的構建過程中就可以求出)然後就是一個區間覆蓋,因為我懶得寫貪心,就寫了線段樹優化的DP。 #include<iostream> #include<cstring> #include<cstdio> #include<
POJ 2376 Cleaning Shifts (線段樹優化DP)
題目大意:給你很多條線段,開頭結尾是$[l,r]$,讓你覆蓋整個區間$[1,T]$,求最少的線段數 題目傳送門 線段樹優化$DP$裸題.. 先去掉所有能被其他線段包含的線段,這種線段一定不在最優解裡 排序,讓所有線段構成左右端點位置都遞增的排列 定義$f[i]$表示第$i$條線段,覆蓋到第$i$條線
BZOJ 1835 [ZJOI2010]基站選址 (線段樹優化DP)
geo har while 位置 如何 lse problem space getchar 題目大意:略 洛谷題面傳送門 BZOJ題面傳送門 註意題目的描述,是村莊在一個範圍內去覆蓋基站,而不是基站覆蓋村莊,別理解錯了 定義$f[i][k]$表示只考慮前i個村莊,一共建
bzoj1835(線段樹優化dp)
神題啊,好吧,應該是因為我太弱了。。。 設f[i][k]表示到第i個村莊,第i個村莊一定會建基站,已經建了k個基站的最小費用. f[i][k]=min{f[j][k-1]+cost(j+1,i-1)}+c[i]; //注意本題線段樹維護的是當我們列舉i的時候,線段
【線段樹優化DP】 HDU 3698 Let the light guide us
ans build tchar bit txt 。。 bre hellip har 這篇博客主要是發現了…… #define cmin(x,y) (x>y?x=y:0) 要比 void cmin(int &x,int y){i
CF940E Cashback 線段樹優化DP
## 題目描述 Since you are the best Wraith King, Nizhniy Magazin «Mir» at the centre of Vinnytsia is offering you a discount. You are given an array a a a of
Atcoder Regular contest 085F NRE 線段樹+DP
題意:給你兩個序列,a全部為0,b給出,給出一些區間,可以把a上的這些區間變為全1,要求操作以後兩個序列對應位置不相同的個數最小,n<=2e5. 說實話這種區間操作很容易想到線段樹,但是我沒想到
AtCoder Regular Contest 088 E - Papple Sort(樹狀數組+結論)
stream line sed post regular sum lib printf char 結論:每次把字符丟到最外面最優,用樹狀數組統計答案,把字符放到最外邊後可以當成消失了,直接在樹狀數組上刪掉就好。 感性理解是把字符丟到中間會增加其他字符的移動次數,但
[Atcoder Regular Contest 060] Tutorial
sts type link b- nbsp target AD SQ isp Link: ARC060 傳送門 C: #include <bits/stdc++.h> using namespace std; typedef long long ll; c