[bzoj4695]最假女选手
整体思路类似于hdu5306,在线段树上维护区间内最大值及个数、严格次大值、最小值及个数、严格次小值和区间和,即可支持$o(\log n)$查询
修改时,区间加直接维护即可,区间取$\min$的做法与该题相同——
修改时,搜索至完全覆盖的区间后再分类讨论:
1.若修改值大于严格次大值,可以打上懒标记并维护上述信息
2.若修改值不超过严格次大值,继续递归下去
区间取$\max$和取$\min$类似,利用最小值的信息即可(另外,注意当区间内权值种类数$\le 2$时还要修改另一边的值和标记)
考虑这样的修改复杂度,定义势能为线段树上与父亲最大值不同的节点树深度和,为了方便不妨仅考虑区间加和区间取$\min$这两种操作(区间取$\max$是类似的),并分别讨论:
1.对于区间加,至多使得被访问的节点计入势能,即均摊复杂度为$o(\log^{2}n)$
2.对于区间取$\min$,显然这不会使得任何节点对势能贡献增加,下面考虑对势能贡献减少的节点(即操作前与父亲最大值不同且操作后相同),具体分析如下:
取出所有访问过的位置(不包括打标记的位置),构成一棵二叉树
考虑这棵二叉树的叶子,必然有其不是原线段树的叶子且其两个儿子都被打上标记
根据递归过程,两个儿子的次大值均$<x$,而父亲的次大值$\ge x$,因此父亲的最大值和次大值分别为某个儿子的最大值,即恰有一个儿子初始对势能有贡献(即为次大值的)
注意到父亲的次大值$\ge x$,因此父亲和该儿子操作后最大值均为$x$,即其对势能贡献减少,且根据定义减小的是其深度,那么不难得到均摊复杂度为$o(1)$
势能范围为$[0,n\log n]$,因此时间复杂度为$o(n\log n+m\log^{2}n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define oo 0x3f3f3f3f 5 #define ll long long 6 #define L (k<<1) 7 #define R (L+1) 8 #define mid (l+r>>1) 9 int t,n,m,p,x,y,z,a[N],len[N<<2],mx[N<<2],mn[N<<2],cnt_mx[N<<2],cnt_mn[N<<2],cmx[N<<2],cmn[N<<2],tag[N<<2],tag_mx[N<<2],tag_mn[N<<2]; 10 ll sum[N<<2]; 11 void upd(int k,int x){ 12 tag[k]+=x,mx[k]+=x,mn[k]+=x,sum[k]+=(ll)len[k]*x; 13 if (cmx[k]!=-oo)cmx[k]+=x; 14 if (cmn[k]!=oo)cmn[k]+=x; 15 if (tag_mx[k]!=oo)tag_mx[k]+=x; 16 if (tag_mn[k]!=oo)tag_mn[k]+=x; 17 } 18 void upd_mx(int k,int x){ 19 if (mx[k]<=x)return; 20 sum[k]+=(ll)cnt_mx[k]*(x-mx[k]); 21 if (mn[k]==mx[k]){ 22 mn[k]=x; 23 if (tag_mn[k]!=oo)tag_mn[k]=x; 24 } 25 if (cmn[k]==mx[k])cmn[k]=x; 26 tag_mx[k]=mx[k]=x; 27 } 28 void upd_mn(int k,int x){ 29 if (mn[k]>=x)return; 30 sum[k]+=(ll)cnt_mn[k]*(x-mn[k]); 31 if (mx[k]==mn[k]){ 32 mx[k]=x; 33 if (tag_mx[k]!=oo)tag_mx[k]=x; 34 } 35 if (cmx[k]==mn[k])cmx[k]=x; 36 tag_mn[k]=mn[k]=x; 37 } 38 void up(int k){ 39 mx[k]=max(mx[L],mx[R]),mn[k]=min(mn[L],mn[R]),sum[k]=sum[L]+sum[R]; 40 cnt_mx[k]=cnt_mn[k]=0,cmx[k]=max(cmx[L],cmx[R]),cmn[k]=min(cmn[L],cmn[R]); 41 if (mx[k]==mx[L])cnt_mx[k]+=cnt_mx[L]; 42 else cmx[k]=max(cmx[k],mx[L]); 43 if (mx[k]==mx[R])cnt_mx[k]+=cnt_mx[R]; 44 else cmx[k]=max(cmx[k],mx[R]); 45 if (mn[k]==mn[L])cnt_mn[k]+=cnt_mn[L]; 46 else cmn[k]=min(cmn[k],mn[L]); 47 if (mn[k]==mn[R])cnt_mn[k]+=cnt_mn[R]; 48 else cmn[k]=min(cmn[k],mn[R]); 49 } 50 void down(int k){ 51 if (tag[k]){ 52 upd(L,tag[k]); 53 upd(R,tag[k]); 54 tag[k]=0; 55 } 56 if (tag_mx[k]!=oo){ 57 upd_mx(L,tag_mx[k]); 58 upd_mx(R,tag_mx[k]); 59 tag_mx[k]=oo; 60 } 61 if (tag_mn[k]!=oo){ 62 upd_mn(L,tag_mn[k]); 63 upd_mn(R,tag_mn[k]); 64 tag_mn[k]=oo; 65 } 66 } 67 void build(int k,int l,int r){ 68 len[k]=r-l+1,tag[k]=0,tag_mx[k]=tag_mn[k]=oo; 69 if (l==r){ 70 mx[k]=mn[k]=sum[k]=a[l]; 71 cnt_mx[k]=cnt_mn[k]=1,cmx[k]=-oo,cmn[k]=oo; 72 return; 73 } 74 build(L,l,mid); 75 build(R,mid+1,r); 76 up(k); 77 } 78 void update_add(int k,int l,int r,int x,int y,int z){ 79 if ((l>y)||(x>r))return; 80 if ((x<=l)&&(r<=y)){ 81 upd(k,z); 82 return; 83 } 84 down(k); 85 update_add(L,l,mid,x,y,z); 86 update_add(R,mid+1,r,x,y,z); 87 up(k); 88 } 89 void update_max(int k,int l,int r,int x,int y,int z){ 90 if ((l>y)||(x>r))return; 91 if ((x<=l)&&(r<=y)&&(cmn[k]>z)){ 92 upd_mn(k,z); 93 return; 94 } 95 down(k); 96 update_max(L,l,mid,x,y,z); 97 update_max(R,mid+1,r,x,y,z); 98 up(k); 99 } 100 void update_min(int k,int l,int r,int x,int y,int z){ 101 if ((l>y)||(x>r))return; 102 if ((x<=l)&&(r<=y)&&(cmx[k]<z)){ 103 upd_mx(k,z); 104 return; 105 } 106 down(k); 107 update_min(L,l,mid,x,y,z); 108 update_min(R,mid+1,r,x,y,z); 109 up(k); 110 } 111 int query_max(int k,int l,int r,int x,int y){ 112 if ((l>y)||(x>r))return -oo; 113 if ((x<=l)&&(r<=y))return mx[k]; 114 down(k); 115 return max(query_max(L,l,mid,x,y),query_max(R,mid+1,r,x,y)); 116 } 117 int query_min(int k,int l,int r,int x,int y){ 118 if ((l>y)||(x>r))return oo; 119 if ((x<=l)&&(r<=y))return mn[k]; 120 down(k); 121 return min(query_min(L,l,mid,x,y),query_min(R,mid+1,r,x,y)); 122 } 123 ll query_sum(int k,int l,int r,int x,int y){ 124 if ((l>y)||(x>r))return 0; 125 if ((x<=l)&&(r<=y))return sum[k]; 126 down(k); 127 return query_sum(L,l,mid,x,y)+query_sum(R,mid+1,r,x,y); 128 } 129 int main(){ 130 scanf("%d",&n); 131 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 132 build(1,1,n); 133 scanf("%d",&m); 134 for(int i=1;i<=m;i++){ 135 scanf("%d%d%d",&p,&x,&y); 136 if (p==1){ 137 scanf("%d",&z); 138 update_add(1,1,n,x,y,z); 139 } 140 if (p==2){ 141 scanf("%d",&z); 142 update_max(1,1,n,x,y,z); 143 } 144 if (p==3){ 145 scanf("%d",&z); 146 update_min(1,1,n,x,y,z); 147 } 148 if (p==4)printf("%lld\n",query_sum(1,1,n,x,y)); 149 if (p==5)printf("%d\n",query_max(1,1,n,x,y)); 150 if (p==6)printf("%d\n",query_min(1,1,n,x,y)); 151 } 152 return 0; 153 }