bzoj3272 Zgg吃东西
题目描述:
题解:
线段树模拟费用流。
想法和种树有点类似。
每次取区间内权值和最大的一段,然后整体乘$-1$,代表再次选中时会去掉之前的影响。
线段树维护一堆东西……
小白逛公园双倍快乐。乘$-1$时交换正反。
[滑稽]
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,m; int chg[50][2]; struct n_8 { int w,wl,wr,wu,pl,pr,pll,prr; n_8(){} n_8(int w,int wl,int wr,int wu,int pl,int pr,int pll,int prr):w(w),wl(wl),wr(wr),wu(wu),pl(pl),pr(pr),pll(pll),prr(prr){} }; void chkmax(int&a,int&b,int c,int d,int e,int f) { if(c>e)a=c,b=d; else a=e,b=f; } void chkmax(int&a,int&b,int&c,int d,int e,int f,int g,int h,int i) { if(d>g)a=d,b=e,c=f; else a=g,b=h,c=i; } void chkmin(int&a,int&b,int c,int d,int e,int f) { if(c<e)a=c,b=d; else a=e,b=f; } void chkmin(int&a,int&b,int&c,int d,int e,int f,int g,int h,int i) { if(d<g)a=d,b=e,c=f; else a=g,b=h,c=i; } void Swap(int&a,int&b) { swap(a,b); a=-a,b=-b; } n_8 operator + (n_8 a,n_8 b) { n_8 c; c.w = a.w+b.w; chkmax(c.wl,c.pll,a.wl,a.pll,a.w+b.wl,b.pll); chkmax(c.wr,c.prr,b.wr,b.prr,b.w+a.wr,a.prr); chkmax(c.wu,c.pl,c.pr,a.wu,a.pl,a.pr,b.wu,b.pl,b.pr); chkmax(c.wu,c.pl,c.pr,c.wu,c.pl,c.pr,a.wr+b.wl,a.prr,b.pll); return c; } struct segtree { int w[N<<2],wl[N<<2],wr[N<<2],wu[N<<2],pl[N<<2],pr[N<<2],pll[N<<2],prr[N<<2]; int _wl[N<<2],_wr[N<<2],_wu[N<<2],_pl[N<<2],_pr[N<<2],_pll[N<<2],_prr[N<<2]; bool res[N<<2]; void update(int u) { w[u] = w[u<<1]+w[u<<1|1]; chkmax(wl[u],pll[u],wl[u<<1],pll[u<<1],w[u<<1]+wl[u<<1|1],pll[u<<1|1]); chkmax(wr[u],prr[u],wr[u<<1|1],prr[u<<1|1],w[u<<1|1]+wr[u<<1],prr[u<<1]); chkmin(_wl[u],_pll[u],_wl[u<<1],_pll[u<<1],w[u<<1]+_wl[u<<1|1],_pll[u<<1|1]); chkmin(_wr[u],_prr[u],_wr[u<<1|1],_prr[u<<1|1],w[u<<1|1]+_wr[u<<1],_prr[u<<1]); chkmax(wu[u],pl[u],pr[u],wu[u<<1],pl[u<<1],pr[u<<1],wu[u<<1|1],pl[u<<1|1],pr[u<<1|1]); chkmax(wu[u],pl[u],pr[u],wu[u],pl[u],pr[u],wr[u<<1]+wl[u<<1|1],prr[u<<1],pll[u<<1|1]); chkmin(_wu[u],_pl[u],_pr[u],_wu[u<<1],_pl[u<<1],_pr[u<<1],_wu[u<<1|1],_pl[u<<1|1],_pr[u<<1|1]); chkmin(_wu[u],_pl[u],_pr[u],_wu[u],_pl[u],_pr[u],_wr[u<<1]+_wl[u<<1|1],_prr[u<<1],_pll[u<<1|1]); } void reser(int u) { res[u]^=1; w[u] = -w[u]; Swap(wl[u],_wl[u]);Swap(wr[u],_wr[u]);Swap(wu[u],_wu[u]); swap(pl[u],_pl[u]);swap(pr[u],_pr[u]); swap(pll[u],_pll[u]);swap(prr[u],_prr[u]); } void pushdown(int u) { if(res[u]) { reser(u<<1); reser(u<<1|1); res[u] = 0; } } void build(int l,int r,int u) { if(l==r) { int x;read(x); w[u] = wu[u] = _wu[u] = wl[u] = _wl[u] = wr[u] = _wr[u] = x; pl[u]=pr[u]=pll[u]=prr[u]=_pl[u]=_pr[u]=_pll[u]=_prr[u]=l; return ; } int mid = (l+r)>>1; build(l,mid,u<<1); build(mid+1,r,u<<1|1); update(u); } void insert(int l,int r,int u,int qx,int d) { if(l==r) { w[u] = wu[u] = _wu[u] = wl[u] = _wl[u] = wr[u] = _wr[u] = d; return ; } pushdown(u); int mid = (l+r)>>1; if(qx<=mid)insert(l,mid,u<<1,qx,d); else insert(mid+1,r,u<<1|1,qx,d); update(u); } void erase(int l,int r,int u,int ql,int qr) { if(l==ql&&r==qr) { reser(u); return ; } pushdown(u); int mid = (l+r)>>1; if(qr<=mid)erase(l,mid,u<<1,ql,qr); else if(ql>mid)erase(mid+1,r,u<<1|1,ql,qr); else erase(l,mid,u<<1,ql,mid),erase(mid+1,r,u<<1|1,mid+1,qr); update(u); } n_8 query(int l,int r,int u,int ql,int qr) { if(l==ql&&r==qr)return n_8(w[u],wl[u],wr[u],wu[u],pl[u],pr[u],pll[u],prr[u]); pushdown(u); int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,u<<1,ql,qr); else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr); else return query(l,mid,u<<1,ql,mid)+query(mid+1,r,u<<1|1,mid+1,qr); } }tr; int main() { read(n); tr.build(1,n,1); read(m); int op,x,y,w; for(int i=1;i<=m;i++) { read(op),read(x),read(y); if(!op)tr.insert(1,n,1,x,y); else { read(w); n_8 tmp = tr.query(1,n,1,x,y); int ans = 0; for(int j=1;j<=w;j++) { if(tmp.wu>0) { ans+=tmp.wu; chg[j][0]=tmp.pl,chg[j][1]=tmp.pr; tr.erase(1,n,1,tmp.pl,tmp.pr); tmp = tr.query(1,n,1,x,y); }else { w = j-1; break; } } printf("%d\n",ans); for(int j=1;j<=w;j++) tr.erase(1,n,1,chg[j][0],chg[j][1]); } } return 0; }
压行大法好。