對於每一行,這些障礙將其劃分爲若干段,記第$i$行($y=i$時)從左到右第$j$段爲$[l_{i,j},r_{i,j}]$c++
顯然一條路徑剛好通過每一行中的一段,且兩種方案不一樣當且僅當其中通過的一段不一樣ide
對於某一條路徑,令$a_{i}$爲其通過第$i$行時的段,則合法當且僅當
$$
a_{1}=1且\forall 2\le i\le n,[\max_{j=1}^{i-1}l_{j,a_{j}},r_{i-1,a_{i-1}}]\cap [l_{i,a_{i}},r_{i,a_{i}}]\ne \empty
$$
且兩種方案不一樣當且僅當$a_{i}$不一樣,題目即變爲統計$a_{i}$的方案spa
考慮dp統計,令$f_{i,j}$表示僅考慮$a_{1},a_{2},...,a_{i}$,知足$\max_{k=1}^{i}l_{k,a_{k}}=j$且合法(僅考慮肯定的部分)的方案數,初始狀態因爲強制$a_{1}=1$,即$f_{1,1}=1$it
同時有交的條件,也就保證了$\max_{j=1}^{i}l_{j,a_{j}}$剛好在$a_{i}$所在段中,即經過$j$便可肯定$a_{i}$class
由此,就能夠獲得暴力轉移的式子,即
$$
f_{i,j}=\begin{cases}0&(a_{i}不存在)\\
f_{i-1,j}&(l_{i,a_{i}}\ne j)\\\sum_{j'=l_{i-1,a_{i-1}}}^{j}f_{i-1,j'}&(l_{i,a_{i}}=j)\end{cases}
$$
(其中$a_{i}$和$a_{i-1}$分別爲第$i$和$i-1$行包含$j$的段編號)date
咱們簡單的對其更進一步的討論,即找出全部知足$f_{i,j}=f_{i-1,j}$的狀況都分入第2類,即
$$
f_{i,j}=\begin{cases}0&((a_{i}不存在)\and (a_{i-1}存在))\\
f_{i-1,j}&((a_{i}和a_{i-1}都不存在)\or (l_{i,a_{i}}\ne j)\and (l_{i-1,a_{i-1}}=j))\\\sum_{j'=l_{i-1,a_{i-1}}}^{j}f_{i-1,j'}&((l_{i,a_{i}}=j)\and (l_{i-1,a_{i-1}}\ne j))\end{cases}
$$
考慮用線段樹維護當前$f_{i-1}$這個長爲$n$的序列,那麼僅須要修改第1類和第3類的位置im
用set來維護障礙(直接維護全部$y_{1}\le i\le y_{2}$的區間$[x_{1},x_{2}]$),差分的插入和刪除統計
對於第1類,這些位置必然被全部新插入障礙的區間包含(雖然這些區間可能以前也有障礙,但這樣的數量級已經能夠保證),總次數顯然爲$o(k)$查詢
對於第3類,也必然是新插入的障礙的$x+1$的位置(其中$x$爲插入障礙的右端點)且未被障礙覆蓋,在set中找到左端點小於等於$x+1$中最大的的右端點$x'$,對$[x'+1,x+1]$求和做爲$f_{i,x+1}$便可img
(特別的,當不存在這樣的區間時,令$x'$爲0)
但找到$x'$事實上比較困難,可能須要手寫平衡樹,注意到被障礙覆蓋的位置$f$必定是0,所以$x'$只須要知足$[x'+1,x+1]$這一段僅有一個後綴(能夠爲空)無障礙便可
那麼只須要選擇左端點小於等於$x$中最大的左端點所對應的右端點做爲$x'$便可
(另外須要記錄答案統一修改,防止修改和查詢之間相互影響)
最終的答案不是$\sum_{i=1}^{n}f_{m,i}$,而是要對找到右端點最大的障礙來統計,一樣的緣由也能夠選左端點最大的右端點來計算
總複雜度即爲$o(m+k\log n)$,能夠經過
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define mod 1000000007 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 #define fi first 9 #define se second 10 vector<pair<int,int> >v,v_add[N],v_del[N]; 11 multiset<pair<int,int> >s; 12 multiset<pair<int,int> >::iterator it; 13 int n,m,k,f[N<<2],tag[N<<2]; 14 void upd(int k){ 15 tag[k]=1; 16 f[k]=0; 17 } 18 void up(int k){ 19 f[k]=(f[L]+f[R])%mod; 20 } 21 void down(int k){ 22 if (tag[k]){ 23 upd(L); 24 upd(R); 25 tag[k]=0; 26 } 27 } 28 void update_val(int k,int l,int r,int x,int y){ 29 if (l==r){ 30 f[k]=y; 31 return; 32 } 33 down(k); 34 if (x<=mid)update_val(L,l,mid,x,y); 35 else update_val(R,mid+1,r,x,y); 36 up(k); 37 } 38 void update_zero(int k,int l,int r,int x,int y){ 39 if ((l>y)||(x>r))return; 40 if ((x<=l)&&(r<=y)){ 41 upd(k); 42 return; 43 } 44 down(k); 45 update_zero(L,l,mid,x,y); 46 update_zero(R,mid+1,r,x,y); 47 up(k); 48 } 49 int query(int k,int l,int r,int x,int y){ 50 if ((l>y)||(x>r))return 0; 51 if ((x<=l)&&(r<=y))return f[k]; 52 down(k); 53 return (query(L,l,mid,x,y)+query(R,mid+1,r,x,y))%mod; 54 } 55 int main(){ 56 scanf("%d%d%d",&n,&m,&k); 57 update_val(1,1,n,1,1); 58 for(int i=1;i<=k;i++){ 59 int x1,y1,x2,y2; 60 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 61 v_add[y1].push_back(make_pair(x1,x2)); 62 if (y2<m)v_del[y2+1].push_back(make_pair(x1,x2)); 63 } 64 for(int i=1;i<=m;i++){ 65 v.clear(); 66 for(int j=0;j<v_add[i].size();j++){ 67 int x=v_add[i][j].se+1; 68 if ((i>1)&&(x<=n)){ 69 it=s.lower_bound(make_pair(x+1,0)); 70 int xx=1; 71 if (it!=s.begin())xx=(*--it).se+1; 72 if (xx<x)v.push_back(make_pair(x,query(1,1,n,xx,x))); 73 } 74 } 75 for(int j=0;j<v.size();j++)update_val(1,1,n,v[j].fi,v[j].se); 76 for(int j=0;j<v_add[i].size();j++){ 77 s.insert(v_add[i][j]); 78 update_zero(1,1,n,v_add[i][j].fi,v_add[i][j].se); 79 } 80 for(int j=0;j<v_del[i].size();j++)s.erase(s.find(v_del[i][j])); 81 } 82 if (s.size())printf("%d",query(1,1,n,(*--s.end()).se+1,n)); 83 else printf("%d",query(1,1,n,1,n)); 84 }