bzoj 4504 - 主席樹+區間修改
阿新 • • 發佈:2018-10-31
題目連結:https://darkbzoj.cf/problem/4504
解題思路:
題目跟洛谷P2048 差不多,主要差在區間數只能統計一次,洛谷那題區間一樣的數可以重複統計.
那麼就可以用pre[i]表示i這個數上一次出現的位置在哪,那麼對於新的主席樹更新區間就是(pre[i],i),之後的操作與洛谷P2048幾乎相同
https://blog.csdn.net/a1214034447/article/details/83246731
#include<bits/stdc++.h> #define inf 0x3f3f3f3f #define lson l,mid #define rson mid+1,r using namespace std; typedef long long ll; const int mx = 2e5 + 10; const int mod = 1e9+7; const ll INF = -1e16; int n,m,root[mx]; int a[mx],rs[mx*30]; int siz,ls[mx*30],d; ll add[mx*30]; struct node { int rt,l,r,p; ll c; bool operator < (node A)const { return c < A.c; } }; struct data { int ps; ll Ma; }s[mx*30]; map <int,int> mp; priority_queue <node> st; void build(int& rt,int l,int r) { rt = siz++; if(l==r){ s[rt].ps = l; return ; } int mid = (l+r)>>1; build(ls[rt],lson); build(rs[rt],rson); } data up(data a,data b) { if(b.Ma>a.Ma) return b; return a; } void update(int x,int &y,int l,int r,int L,int R) { y = siz++; s[y] = s[x],add[y] = add[x]; ls[y] = ls[x],rs[y] = rs[x]; if(L<=l&&r<=R){ add[y] += d; s[y].Ma += d; return ; } int mid = (l+r)>>1; if(R<=mid) update(ls[x],ls[y],lson,L,R); else if(L>mid) update(rs[x],rs[y],rson,L,R); else{ update(ls[x],ls[y],lson,L,mid); update(rs[x],rs[y],rson,mid+1,R); } s[y] = up(s[ls[y]],s[rs[y]]); s[y].Ma += add[y]; } data query(int rt,int l,int r,int L,int R) { if(L<=l&&r<=R) return s[rt]; int mid = (l+r)>>1; data ans = {0,INF}; if(L<=mid) ans = up(ans,query(ls[rt],lson,L,R)); if(R>mid) ans = up(ans,query(rs[rt],rson,L,R)); return data{ans.ps,ans.Ma+add[rt]}; } int main() { scanf("%d%d",&n,&m); build(root[0],1,n); for(int i=1;i<=n;i++){ scanf("%d",a+i); d = a[i]; update(root[i-1],root[i],1,n,mp[a[i]]+1,i); mp[a[i]] = i; data ret = query(root[i],1,n,1,i); st.push(node{root[i],1,i,ret.ps,ret.Ma}); } data ret;node now; while(m--){ now = st.top(); st.pop(); if(now.p-now.l>0){ ret = query(now.rt,1,n,now.l,now.p-1); st.push(node{now.rt,now.l,now.p-1,ret.ps,ret.Ma}); } if(now.r-now.p>0){ ret = query(now.rt,1,n,now.p+1,now.r); st.push(node{now.rt,now.p+1,now.r,ret.ps,ret.Ma}); } //cout << now.c << endl; } printf("%lld\n",now.c); return 0; }