1. 程式人生 > >codeforces 997E(線段樹)

codeforces 997E(線段樹)

分析 分享 build const 延遲 str ddt none can

分析:

  首先考慮如何計算整個數組有多少個good區間

  容易發現一個區間是good區間當且僅當max-min-len=-1,且任意區間max-min-len>=-1

  我們可以枚舉右端點,然後維護前面每個位置到當前右端點的max-min-len值,容易發現我們只需要維護區間最小值和最小值的個數就行了,於是用線段樹即可

  於是我們可以得到以某個點為右端點的時候合法區間總數,那麽我們把每次的結果加起來,就得到了整個數組有多少個good區間

  每次右端點移動怎麽更新呢?顯然我們只需要用一個max單調棧,一個min單調棧來幫助尋找修改區間,容易知道修改區間的個數是O(n)級別的,所以整個修改是O(nlogn)的

  好,現在我們回到原來的問題,如何求[l,r]內有多少個good區間

  在這個問題中,我們實際上要額外知道“每個區間的歷史答案和”,這是什麽意思呢,比如說在i=7的時候,[4,7]裏的答案存的是有多少個合法的位置是和7匹配的

  但i=6的時候,[4,7]裏的答案存的是有多少個合法的位置是和6匹配的

  我們自然而然就考慮到把每個右端點時刻,一個區間的產生的答案值加起來就行了,但這個時間復雜度是巨大的

  這裏我們仍然可以用延遲標記來解決,比如右端點i枚舉完了,我們可以給[1,i]上個tag,表示這整個區間的歷史答案需要加上現在時刻的答案

  時間復雜度O(nlogn)

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define mp make_pair
  4 const int maxn=120000;
  5 struct wjmzbmr
  6 {
  7     int mi,num,tag;
  8     int time;
  9     long long ans;
 10 }tree[maxn*4+5];
 11 vector<pair<int,int> > q[maxn+5];
 12 long long ans[maxn+5
]; 13 int a[maxn+5],s[maxn+5],s1[maxn+5]; 14 int len,len1; 15 int n,m; 16 void addtag(int k,int x) 17 { 18 tree[k].tag+=x; 19 tree[k].mi+=x; 20 } 21 void addtime(int k,int x) 22 { 23 tree[k].time+=x; 24 tree[k].ans+=1LL*x*tree[k].num; 25 } 26 void pushdown(int k) 27 { 28 if(tree[k].tag) 29 { 30 addtag(k*2,tree[k].tag); 31 addtag(k*2+1,tree[k].tag); 32 tree[k].tag=0; 33 } 34 if(tree[k].time) 35 { 36 if(tree[k].mi==tree[k*2].mi) addtime(k*2,tree[k].time); 37 if(tree[k].mi==tree[k*2+1].mi) addtime(k*2+1,tree[k].time); 38 tree[k].time=0; 39 } 40 } 41 void update(int k) 42 { 43 tree[k].mi=min(tree[k*2].mi,tree[k*2+1].mi); 44 tree[k].ans=tree[k*2].ans+tree[k*2+1].ans; 45 tree[k].num=0; 46 if(tree[k].mi==tree[k*2].mi) tree[k].num+=tree[k*2].num; 47 if(tree[k].mi==tree[k*2+1].mi) tree[k].num+=tree[k*2+1].num; 48 } 49 void build(int k,int l,int r) 50 { 51 if(l>r) return; 52 if(l==r) 53 { 54 tree[k].num=1; 55 tree[k].mi=-1; 56 return; 57 } 58 int mid=(l+r)>>1; 59 build(k*2,l,mid); 60 build(k*2+1,mid+1,r); 61 update(k); 62 } 63 void modify(int k,int l,int r,int ql,int qr,int x) 64 { 65 if(r<ql||l>qr||l>r) return; 66 if(l>=ql&&r<=qr) 67 { 68 addtag(k,x); 69 return; 70 } 71 if(l==r) return; 72 pushdown(k); 73 int mid=(l+r)>>1; 74 modify(k*2,l,mid,ql,qr,x); 75 modify(k*2+1,mid+1,r,ql,qr,x); 76 update(k); 77 } 78 void modify1(int k,int l,int r,int ql,int qr,int x) 79 { 80 if(r<ql||l>qr||l>r) return; 81 if(l>=ql&&r<=qr) 82 { 83 if(tree[k].mi==-1) 84 addtime(k,x); 85 return; 86 } 87 if(l==r) return; 88 pushdown(k); 89 int mid=(l+r)>>1; 90 modify1(k*2,l,mid,ql,qr,x); 91 modify1(k*2+1,mid+1,r,ql,qr,x); 92 update(k); 93 } 94 long long query(int k,int l,int r,int ql,int qr) 95 { 96 if(r<ql||l>qr||l>r) return 0; 97 if(l>=ql&&r<=qr) return tree[k].ans; 98 if(l==r) return 0; 99 pushdown(k); 100 int mid=(l+r)>>1; 101 long long ans=query(k*2,l,mid,ql,qr)+query(k*2+1,mid+1,r,ql,qr); 102 update(k); 103 return ans; 104 } 105 int main() 106 { 107 scanf("%d",&n); 108 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 109 scanf("%d",&m); 110 for(int i=1;i<=m;++i) 111 { 112 int l,r; 113 scanf("%d%d",&l,&r); 114 q[r].push_back(mp(l,i)); 115 } 116 build(1,1,n); 117 for(int i=1;i<=n;++i) 118 { 119 while(len&&a[s[len]]<a[i]) modify(1,1,n,s[len-1]+1,s[len],a[i]-a[s[len]]),--len; 120 s[++len]=i; 121 //for(int j=1;j<=len;++j) printf("%d ",a[s[j]]);printf("\n"); 122 while(len1&&a[s1[len1]]>a[i]) modify(1,1,n,s1[len1-1]+1,s1[len1],a[s1[len1]]-a[i]),--len1; 123 s1[++len1]=i; 124 //for(int j=1;j<=len1;++j) printf("%d ",a[s1[j]]);printf("\n"); 125 modify1(1,1,n,1,i,1); 126 for(auto x:q[i]) ans[x.second]=query(1,1,n,x.first,i); 127 //printf("%lld\n",query(1,1,n,1,i)); 128 //if(i==4) printf("%d\n",tree[2].ans); 129 modify(1,1,n,1,i,-1); 130 131 } 132 for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); 133 return 0; 134 }
View Code

codeforces 997E(線段樹)