[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 } 
View Code

 

posted @ 2021-09-28 15:41  PYWBKTDA  阅读(59)  评论(0编辑  收藏  举报