link
先考慮單點修改的做法:
線段樹上每個節點維護四個資訊:\(sum,pre,suf,ans\)。分別代表區間和,區間最大字首和,區間最大字尾和,區間最大子段和。
合併:\(sum_x=sum_l+sum_r\)
\(pre_x=\max(pre_l,sum_l+pre_r)\)
\(suf_x=\max(suf_r,sum_r+suf_l)\)
\(ans_x=\max(\max(ans_l,ans_r),suf_l+pre_r)\)
考慮如何將修改擴充套件到全域性修改。
假如全域性已經被加上了\(tag\),現在希望求某個點的新的\(sum,pre,suf,ans\)。
\(sum\)非常簡單就不講了。
\(pre\)和\(suf\)具有對稱性,只考慮\(pre\)。
如果將\((x,pre_x)\)看做乙個點(\(pre_x\)表示長度為\(x\)的字首和),那麼我們就是要求\(tag*x+y\)的最大值。
維護乙個凸包,查詢的時候二分一下。
pushup就是將\(pre_\)平移\((len_,sum_)\)之後和\(pre_\)接起來。
現在看\(ans\),在單點修改的部分\(ans\)是與左右兒子的\(ans,suf,pre\)掛鉤的,所以我們類似地考慮。
將\((x,ans_x)\)看做乙個點(\(ans_x\)表示長度為\(x\)的最大子段和),那麼我們就是要求\(tag*x+y\)的最大值。
還是維護乙個凸包,查詢的時候二分一下。
pushup稍微麻煩一點,首先我們合併\(ans_,ans_\),然後求出\(suf_,pre_\)的mincowsky和,再將這兩個凸包合併。
這樣我們可以在一開始建出一棵每個節點維護了\(pre,suf,ans\)三個凸包的線段樹,每次詢問在\(\log\)個節點上二分出最優的\(pre,suf,ans\)然後再按subtask 2的做法合併。這樣子的時間複雜度是\(o(n\log n+m\log^2n)\)的。
我們可以將所有詢問離線之後按\(tag\)排序,這樣凸包上指標的移動就是單調的,因此時間複雜度是\(o((n+m)\log n)\)。
#include#include#includeusing std::sort;
using ll=long long;
namespace io
void flush()
void put(char x)
int read()
void write(ll x)
}using io::read;using io::write;
const int n=300007,m=600007;const ll inf=1ll<<50;
ll max(const ll&a,const ll&b)
int n,m,cnt;ll tag,a[n],ans[m];
struct dot;
dot operator+(const dot&a,const dot&b);}
dot operator-(const dot&a,const dot&b);}
int operator<(const dot&a,const dot&b)
struct convex
void upd(const dot&a)
void ins(const dot&a)
void clr(const int&n);top=n;}
void build()
}ll cal()
};struct data;
data operator+(const data&a,const data&b);}
namespace segtree
void merge(convex&c,convex&a,convex&b,const dot&p)
void merge(convex&c,convex&a,convex&b)
void build(int p,int l,int r,int d)
,pre[p][1]=suf[p][1]=ans[p][1]=,pre[p].top=suf[p].top=ans[p].top=2;
else
),merge(suf[p],suf[rs],suf[ls],),++ans[p].stk,ans[p].clr(r-l);
for(int i=1;i<=ans[ls].top;++i) ans[p].upd(ans[ls][i]);
for(int i=1;i<=ans[rs].top;++i) ans[p].upd(ans[rs][i]);
merge(ans[p],suf[ls],pre[rs]),--ans[p].stk,ans[p][1]=,++ans[p].top,ans[p].build();
} pre[p].now=suf[p].now=ans[p].now=1,ppre[d]=pre[p].stk+pre[p].top,psuf[d]=suf[p].stk+suf[p].top,pans[d]=ans[p].stk+ans[p].top;
}data query(int p,int l,int r,int l,int r)
;if(r<=mid) return query(ls,l,mid,l,r);
if(l>=mid) return query(rs,mid,r,l,r);
return query(ls,l,mid,l,mid)+query(rs,mid,r,mid,r);
}#undef ls
#undef rs
#undef mid
}struct queryq[m];
int operator<(const query&a,const query&b)
int main()
,0ll);
sort(q+1,q+cnt+1),tag=q[1].tag;
for(int i=1;i<=cnt;++i) q[i].tag-=tag;
for(int i=1;i<=n;++i) a[i]+=tag;
segtree::init(),segtree::build(1,0,n,0);
for(int i=1;i<=cnt;++i) tag=q[i].tag,ans[q[i].id]=segtree::query(1,0,n,q[i].l-1,q[i].r).ans;
for(int i=1;i<=cnt;++i) write(ans[i]);
return io::flush(),0;
}
P5071 Ynoi2015 此時此刻的光輝
傳送門 lxl大毒瘤 首先乙個數的因子個數就是這個數的每個質因子的次數 1的積,然後考慮把每個數分解質因子,用莫隊維護,然後我交上去就0分了 如果是上面那樣的話,我們每一次移動指標的時間複雜度是o 這個數的質因子個數 再加上我人傻常數大,t很正常 於是按照memset0的說法,可以預處理質因子的字首...
洛谷 P5072 Ynoi2015 盼君勿忘
給定乙個序列,每次查詢乙個區間 l,r 中所有子串行分別去重後的和mod p 我們考慮每個數的貢獻。即該區間內含有這個數的子串行個數。用補集轉化為不含這個數的子串行個數。那麼,假設這個數在 l,r 內出現了k次,則一共有2 r l 1 2 r l 1 k 個子序列包含這個數。本題可以離線,因此選擇使...
CEOI2015 Day2 世界冰球錦標賽
題目描述 譯自 ceoi2015 day2 t1 ice hockey world championship 今年的世界冰球錦標賽在捷克舉行。bobek 已經抵達布拉格,他不是任何團隊的粉絲,也沒有時間觀念。他只是單純的想去看幾場比賽。如果他有足夠的錢,他會去看所有的比賽。不幸的是,他的財產十分有限...