zoukankan      html  css  js  c++  java
  • loj6253/luogu4062-Yazid的新生舞会

    先考虑部分分(只有01/只有0~7)做法:枚举每个数,把和他相同的设为1,不同的设为-1,然后这个数作为众数贡献的个数就是区间和>0的个数

    推着做,树状数组记前缀和<=x的区间的数量就可以,复杂度$O(8nlogn)$

    如果直接套过来,$O(n^2logn)$肯定是不行的,但可以发现枚举了所有数以后1的个数一共只能有n个,而如果把相邻的-1看成一个,它的数量也是O(n)的

    所以对于1的做法是不变的;对于-1,我们要连起来处理。如果设这段-1之前的和为sum,-1的个数为len可以得到这段-1的贡献,其实就是$[-n,sum-len-1]+[-n,sum-len]+...+[-n,sum-2]$(我们用一个权值线段树来记前缀和为某值的数量)

    为了方便计算,做一个前缀和,就变成了

    $$sumlimits_{i=-n}^{sum-2}{sumlimits_{j=-n}^{i}{a[j]}}-sumlimits_{i=-n}^{sum-len-2}{sumlimits_{j=-n}^{i}{a[j]}}$$

    (可以看出与树状数组做区间加、区间求和的操作类似)

    $$=(sum-2+1)sumlimits_{i=-n}^{sum-2}{a[i]}-sumlimits_{i=-n}^{sum-2}{i*a[i]}-((sum-len-2+1)sumlimits_{i=-n}^{sum-len-2}{a[i]}-sumlimits_{i=-n}^{sum-len-2}{i*a[i]})$$

    然后用线段树维护a[i]和i*a[i]就可以了。而且我们每次枚举完一个以后不能直接memset,不然就变成O(n^2)了,要怎么加进来的就怎么减回去..

    (然后我bzoj上就T了,肯定是评测机太卡了)

      1 #define __Ressed__ <bits/stdc++.h>
      2 #include __Ressed__
      3 #define pa pair<int,int>
      4 #define lowb(x) ((x)&(-(x)))
      5 #define REP(i,n0,n) for(i=n0;i<=n;i++)
      6 #define PER(i,n0,n) for(i=n;i>=n0;i--)
      7 #define MAX(a,b) ((a>b)?a:b)
      8 #define MIN(a,b) ((a<b)?a:b)
      9 #define CLR(a,x) memset(a,x,sizeof(a))
     10 #define rei register int
     11 using namespace std;
     12 typedef long long ll;
     13 const int maxn=5e5+5;
     14 
     15 inline ll rd(){
     16     ll x=0;char c=getchar();int neg=1;
     17     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     18     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     19     return x*neg;
     20 }
     21 
     22 ll v[maxn*4],iv[maxn*4],laz[maxn*4],ans;
     23 int ch[maxn*4][2],pct,root;
     24 int nxt[maxn],hd[maxn];
     25 int L,N,M,num[maxn],tmp[maxn];
     26 
     27 inline void pushdown(int p,int l,int r){
     28     int m=l+r>>1,a=ch[p][0],b=ch[p][1];
     29     if(a){
     30         laz[a]+=laz[p];
     31         v[a]+=laz[p]*(m-l+1);
     32         iv[a]+=laz[p]*(m+l)*(m-l+1)/2;
     33     }
     34     if(b){
     35         laz[b]+=laz[p];
     36         v[b]+=laz[p]*(r-m);
     37         iv[b]+=laz[p]*(r+m+1)*(r-m)/2;
     38     }
     39     laz[p]=0;
     40 }
     41 
     42 inline void update(int p){
     43     v[p]=v[ch[p][0]]+v[ch[p][1]];
     44     iv[p]=iv[ch[p][0]]+iv[ch[p][1]];
     45 }
     46 
     47 void build(int &p,int l,int r){
     48     if(!p) p=++pct;
     49     if(l<r){
     50         int m=l+r>>1;
     51         build(ch[p][0],l,m);
     52         build(ch[p][1],m+1,r);
     53     }
     54 }
     55 
     56 inline void add(int p,int l,int r,int x){
     57     laz[p]+=x;
     58     v[p]+=1ll*(r-l+1)*x;
     59     iv[p]+=1ll*(r+l)*(r-l+1)/2*x;
     60     pushdown(p,l,r);
     61 }
     62 
     63 void ins(int p,int l,int r,int x,int y,int z){
     64     if(x<=l&&r<=y){
     65         add(p,l,r,z);
     66     }else{
     67         pushdown(p,l,r);
     68         int m=l+r>>1;
     69         if(x<=m) ins(ch[p][0],l,m,x,y,z);
     70         if(y>=m+1) ins(ch[p][1],m+1,r,x,y,z);
     71         update(p);
     72     }
     73 }
     74 
     75 ll query(int p,int l,int r,int x){
     76     pushdown(p,l,r);
     77     if(r<=x){
     78         return v[p]*(x+1)-iv[p];
     79     }else{
     80         int m=l+r>>1;ll re;
     81         re=query(ch[p][0],l,m,x);
     82         if(x>=m+1) re+=query(ch[p][1],m+1,r,x);
     83         return re;
     84     }
     85 }
     86 
     87 ll query2(int p,int l,int r,int x){
     88     if(r<=x){
     89         return v[p];
     90     }else{
     91         pushdown(p,l,r);
     92         int m=l+r>>1;ll re;
     93         re=query2(ch[p][0],l,m,x);
     94         if(x>=m+1) re+=query2(ch[p][1],m+1,r,x);
     95         return re;
     96     }
     97 }
     98 
     99 int main(){
    100     // freopen("6253.in","r",stdin);
    101     rei i,j,k;
    102     N=rd();rd();
    103     for(i=1;i<=N;i++) tmp[i]=num[i]=rd();
    104     sort(tmp+1,tmp+N+1);M=unique(tmp+1,tmp+N+1)-tmp-1;
    105     for(i=1;i<=N;i++) num[i]=lower_bound(tmp+1,tmp+M+1,num[i])-tmp;
    106     for(i=N;i;i--){
    107         nxt[i]=hd[num[i]];hd[num[i]]=i;
    108     }
    109     L=N+1;
    110     build(root,-L,L);
    111     ins(root,-L,L,0,0,1);
    112     for(i=1;i<=M;i++){
    113         int sum=0;
    114         for(j=hd[i],k=1;j;j=nxt[j]){
    115             if(k<j){
    116                 ans+=query(root,-L,L,sum-2)-query(root,-L,L,sum-j+k-2);
    117                 ins(root,-L,L,sum-j+k,sum-1,1);
    118                 sum-=j-k;
    119             }sum++;
    120             ans+=query2(root,-L,L,sum-1);
    121             ins(root,-L,L,sum,sum,1);
    122             k=j+1;
    123         }
    124         ans+=query(root,-L,L,sum-2)-query(root,-L,L,sum-N+k-3);
    125         sum=0;
    126         for(j=hd[i],k=1;j;j=nxt[j]){
    127             if(k<j){
    128                 ins(root,-L,L,sum-j+k,sum-1,-1);
    129                 sum-=j-k;
    130             }sum++;
    131             ins(root,-L,L,sum,sum,-1);
    132             k=j+1;
    133         }
    134     }
    135     printf("%lld
    ",ans);
    136     return 0;
    137 }
  • 相关阅读:
    MySQL数据库初识
    Python中面向对象初识到进阶
    python 函数进阶
    Python 函数的初识
    Python的发展与应用
    什么是产品经理 以及职责
    I/O----复制文本文件
    获取次日日期(主要两种方法)
    vector以及array和数组
    编辑软件注释快捷键
  • 原文地址:https://www.cnblogs.com/Ressed/p/9711133.html
Copyright © 2011-2022 走看看