HDU 6406 Taotao Picks Apples (單調棧+樹狀陣列統計+離散化)
阿新 • • 發佈:2019-02-14
#include<bits/stdc++.h> using namespace std; #define debug puts("YES"); #define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++) #define read(x,y) scanf("%d%d",&x,&y) #define ll long long #define lrt int l,int r,int rt #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define root l,r,rt const int maxn =2e5+10; const int mod=1e9+7; const int ub=1e6; ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;} ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} /* 題目大意:給定一個序列,已知這個序列的權值定義為是: 從1位置出發一直到最後,如果拿到比當前水果重量大的則換,如果不是就跳過, 這個序列的權重就是最後拿過的數量, 現在有q次詢問,每次都是把p位置改成q, 詢問這樣的序列權重。 明顯,在尾部維護一個單調棧, 我因為是用樹狀陣列來統計的,所以還要離散化, 空間壓力也大。。。 反正思路就是倒著掃描,在尾部維護一個單調棧, 假設掃描到i位置,則先處理在i處的修改, 如果修改的值比之前維護出來的最大值大,則很簡單,直接cnt[i]+查詢單調棧中比 查詢值大的個數,如果不大於,則需要利用之前維護出來的最大值代替下。 離散化的過程程式碼量稍微大了點,,一些細節的地方把握好這道題還是蠻好想的 */ int n,q,x; int a[maxn],b[maxn],c[maxn];///資料儲存 int cnt[maxn],val[maxn];///資料陣列,計數陣列,判定陣列 int Sk[maxn];///前驅陣列和單調棧陣列 vector<pair<int,int>> qy[maxn]; ///樹狀陣列 int bit[maxn],ans[maxn]; int lowbit(int x){return x&(-x);} void add(int x,int d){for(;x<maxn;bit[x]+=d,x+=lowbit(x));} int sum(int x){int ret=0;for(;x>0;ret+=bit[x],x-=lowbit(x));return ret;} int main() { int t;scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); int cur=0,num=0; for(int i=0;i<=n;i++) qy[i].clear();///清空查詢陣列 for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];///記錄資料集合 for(int i=n+1;i<=n+q;i++) scanf("%d%d",&c[i],&a[i]),b[i]=a[i]; sort(a+1,a+1+n+q); for(int i=1;i<=n+q;i++) { b[i]=lower_bound(a+1,a+1+n+q,b[i])-a+1;///資料離散化 if(i>=n+1) qy[c[i]].push_back(make_pair(b[i],i-n)); } for(int i=1;i<=n;i++) { val[i]=cur,cnt[i]=num;///記錄當前位置的最大值和最大數量 if(i==1||cur<b[i]) num++,cur=b[i]; } int l=0,r=-1;///單調棧 memset(bit,0,sizeof(bit)); for(int i=n;i>=1;i--) { ///先處理查詢,再更新 if(!qy[i].empty()) { for(int j=0;j<qy[i].size();j++) { int qf=qy[i][j].first,qs=qy[i][j].second; if(qf>val[i]) ans[qs]=cnt[i]+sum(maxn-1)-sum(qf)+1; else ans[qs]=cnt[i]+sum(maxn-1)-sum(val[i]); } } while(r>=l&&b[i]>=Sk[r]) { add(Sk[r],-1); r--;///後退 } Sk[++r]=b[i];///先進去 add(b[i],1); } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); } return 0; }