zoukankan      html  css  js  c++  java
  • 【CodeForces】788E New task

    【题意】n个数,每个数有附加属性0或1,初始全为1。m个操作,每个操作可以改变一个数字的属性为0或1。对于每次操作后的序列求有多少子序列满足要求:5个数字,中间3个数相等且属性为1,左右两个数小于等于中间三个数且属性任意。n,m<=10^5。

    【算法】线段树

    【题解】朴素的算法,奇妙的使用>_<!

    离散化后,e[i]为i的权值。

    用a[i]记录比1~i-1中≤e[i]的数的个数,b[i]表示i+1~n中≤e[i]的数的个数。

    a和b可以用树状数组维护,树状数组下标为离散化后的权值,按顺序加入和查询即可。

    那么,显然中间3个数是关键。

    离散化后对于每个权值(1~p)建线段树(1~n),根编号为权值,对于线段树x维护下列值:

    S[k]表示子树k代表区间内x的数量。

    B[k]表示子树k代表区间内只选择第二个点的方案数。

    D[k]表示子树k代表区间内只选择第四个点的方案数。

    BC[k]表示只选择第二三个点的方案数。

    CD[k]表示只选择第三四个点的方案数。

    BCD[k]表示选择第二三四个点的方案数。

    update的方法见代码。

    参考CF用户MemorySlices的代码,非常漂亮,就直接贴了。

    #include<bits/stdc++.h>
    #define N 100005
    #define M 3000005
    #define L(__) (son[__][0])
    #define R(__) (son[__][1])
    #define oo (1<<30)
    using namespace std;
    const int mo=1e9+7;
    int n,m,w[N],lw,a[N],b[N],tr[N],e[N],B[M],BC[M],BCD[M],CD[M],D[M],S[M],son[M][2],len,ans;
    int lowbit(int x){ return x&(-x);}
    void modify(int x){ while(x<=n) tr[x]++,x+=lowbit(x);}
    int query(int x){ int s=0; while(x) s+=tr[x],x-=lowbit(x); return s;}
    void update(int t)
    {
        S[t]=(S[L(t)]+S[R(t)])%mo;
        B[t]=(B[L(t)]+B[R(t)])%mo;
        D[t]=(D[L(t)]+D[R(t)])%mo;
        BC[t]=(BC[L(t)]+BC[R(t)]+1LL*B[L(t)]*S[R(t)])%mo;
        CD[t]=(CD[L(t)]+CD[R(t)]+1LL*S[L(t)]*D[R(t)])%mo;
        BCD[t]=(BCD[L(t)]+BCD[R(t)]+1LL*BC[L(t)]*D[R(t)]+1LL*B[L(t)]*CD[R(t)])%mo;
    }
    void MOD(int t,int l,int r,int s,int x,int y,int d)
    {
        int mid=(l+r)>>1,k=(s>mid);
        if(l==r){ B[t]=x,D[t]=y,S[t]+=d; return ;}
        if(!son[t][k]) son[t][k]=++len;
        if(!k) MOD(L(t),l,mid,s,x,y,d);
        else MOD(R(t),mid+1,r,s,x,y,d);
        update(t);
    }
    int main()
    {
        int i,op,x;
        scanf("%d",&n);
        for(i=1;i<=n;i++) scanf("%d",&e[i]),w[++lw]=e[i];
        sort(w+1,w+lw+1),lw=unique(w+1,w+lw+1)-w-1;
        for(i=1;i<=n;i++) e[i]=lower_bound(w+1,w+lw+1,e[i])-w;
        memset(tr,0,sizeof(tr));
        for(i=1;i<=n;i++) a[i]=query(e[i]),modify(e[i]);
        memset(tr,0,sizeof(tr));
        for(i=n;i>=1;i--) b[i]=query(e[i]),modify(e[i]);
        len=lw;
        for(i=1;i<=n;i++){
            ans=(ans-BCD[e[i]]+mo)%mo;
            MOD(e[i],1,n,i,a[i],b[i],1);
            ans=(ans+BCD[e[i]])%mo;
          }
        scanf("%d",&m);
        while(m--){
            scanf("%d %d",&op,&x);
            ans=(ans-BCD[e[x]]+mo)%mo;
            if(op==1)
                MOD(e[x],1,n,x,0,0,-1);
            else
                MOD(e[x],1,n,x,a[x],b[x],1);
            ans=(ans+BCD[e[x]])%mo;
            printf("%d
    ",ans);
          }
        return 0;
    }
    View Code

    更神奇的操作:http://blog.csdn.net/gjghfd/article/details/74897844 留坑

  • 相关阅读:
    python(7)-pycharm mac和windows专业版安装破解
    Navicat Premium15激活 安装与激活(转载) 有效!!
    PHP 冒泡排序
    PHP 插入排序 -- 希尔排序
    PHP 插入排序 -- 折半查找
    PHP 插入排序 -- 直接插入排序
    PHP 哈夫曼的实现
    PHP call_user_func的一些用法和注意点
    PHP 组件注册的例子
    PHP 奇葩的debug_zval_dump的输出
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7190919.html
Copyright © 2011-2022 走看看