• 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)


    洛谷题目传送门

    一血祭

    向dllxl致敬!

    算是YNOI中比较清新的吧,毕竟代码只有1.25k。

    首先我们对着题意模拟,寻找一些思路。

    每次选了一个最大的数后,它和它周围两个数都要减一。这样无论如何,我们都选不到旁边那两个数,只有第一次选的那个数会对答案产生它的大小的贡献。

    于是就可以写出一个(O(nmlog n))的暴力用来对拍了

    #include<bits/stdc++.h>
    #define LL long long
    #define R register int
    #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
    using namespace std;
    const int SZ=1<<19,N=1e5+9;
    char buf[SZ],*ie=buf+SZ,*ip=ie-1;
    inline int in(){
        G;while(*ip<'-')G;
        R x=*ip&15;G;
        while(*ip>'-'){x*=10;x+=*ip&15;G;}
        return x;
    }
    int a[N],b[N];
    bool vis[N];
    inline bool Cmp(R&x,R y){
        return a[x]>a[y]||(a[x]==a[y]&&x<y);
    }
    int main(){
        R n=in();
        for(R i=1;i<=n;++i)a[i]=in();
        for(R q=in();q--;){
            a[in()]=in();
            for(R i=1;i<=n;++i)b[i]=i;
            sort(b+1,b+n+1,Cmp);
            memset(vis+1,0,n);
            LL ans=0;
            for(R i=1;i<=n;++i){
                if(vis[b[i]])continue;
                vis[b[i]-1]=vis[b[i]]=vis[b[i]+1]=1;
                ans+=a[b[i]];
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    进一步观察,对于一个序列中的一个极长单调区间,我们取到了最大的、第三大的、第五大的。。。

    考虑用set维护好序列的所有极值点,相邻两个极值点所包含区间的贡献就可以通过树状数组查区间和直接算(注意分奇偶)。

    单点修改的时候,只会影响到自己周围至多三个的极值点状态、以及左右各至多两个区间的单调性,暴力删掉原来的贡献再加新的贡献就好了。

    统计答案时细节很多,边界问题也很多,想清楚后再动手还是很舒服的。

    时间复杂度(O((n+m)log n)),因为数据范围不怎么卡(这一点也是YNOI极罕见的)所以蒟蒻直接牺牲常数来减少代码长度了qaq

    #include<bits/stdc++.h>
    #define LL long long
    #define I inline
    #define R register int
    #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
    using namespace std;
    typedef set<int>::iterator IT;
    const int SZ=1<<19,N=1e5+9;
    char buf[SZ],*ie=buf+SZ,*ip=ie-1;
    inline int in(){
        G;while(*ip<'-')G;
        R x=*ip&15;G;
        while(*ip>'-'){x*=10;x+=*ip&15;G;}
        return x;
    }
    int n,a[N];LL ans;set<int>s;
    struct BIT{
        LL a[N];
        I void Upd(R i,R v){
            for(;i<N;i+=i&-i)a[i]+=v;
        }
        I void Qry(R l,R r,LL v){
            for(R i=r;i;i-=i&-i)v+=a[i];
            for(R i=l;i;i-=i&-i)v-=a[i];
        }
    }b[2];
    #define ODD(O) ((*l^*O(j=l))&1)
    I void Calc(IT l,IT r,R op){
        IT i,j;LL sum=*l&&a[*l+1]>a[*l]&&!ODD(--)&&!ODD(++)?a[*l]:0;
        for(i=l++;i!=r;i=l++)
            if(a[*l]>a[*i])b[*l&1].Qry(*i,*l,sum);
            else b[*i&1].Qry(*i,*l-ODD(++),sum);
        ans+=sum*op;
    }
    I void Chk(R x){
        if((a[x]>a[x-1])!=(a[x+1]>a[x]))s.insert(x);
        else s.erase(x);
    }
    I void Upd(R x){
        R y=in();
        IT i=s.lower_bound(x),l=i,r=i;
        --l;if(l!=s.begin())--l;
        ++r;if(r==s.end()||(*i==x&&++r==s.end()))--r;
        Calc(l,r,-1);
        b[x&1].Upd(x,y-a[x]);a[x]=y;
        Chk(x);if(x>1)Chk(x-1);if(x<n)Chk(x+1);
        Calc(l,r,1);
    }
    int main(){
        n=in();s.insert(0);s.insert(n+1);
        for(R i=1;i<=n;++i)Upd(i);
        for(R q=in();q;--q)Upd(in()),printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    7/31 CSU-ACM2018暑期训练7-贪心
    树状数组
    洛谷 P2947 [USACO09MAR]向右看齐Look Up【单调栈】
    如何求先序排列和后序排列——hihocoder1049+洛谷1030+HDU1710+POJ2255+UVA548【二叉树递归搜索】
    HDU 1611 敌兵布阵【线段树模板】
    Poj 2112 Optimal Milking (多重匹配+传递闭包+二分)
    Hdu 5361 In Touch (dijkatrs+优先队列)
    Codeforces Round #Pi (Div. 2)
    Hdu 5358 First One (尺取法+枚举)
    Poj 3189 Steady Cow Assignment (多重匹配)
  • 原文地址:https://www.cnblogs.com/flashhu/p/10493435.html
Copyright © 2020-2023  润新知