[cf720D]Slalom

對於每一行,這些障礙將其劃分爲若干段,記第$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)$,能夠經過

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
 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 } 
View Code
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息