zoukankan      html  css  js  c++  java
  • [树状数组][倍增]luogu P6619 [省选联考 2020 A/B卷] 冰火战士

    题面

    https://www.luogu.com.cn/problem/P6619

    分析

    题目说的复杂,不过这种逐个对战多询问的基本上都有只和双方最值有关的结论,这题也不例外

    简单整理可得对战消耗的能量是 $2 imes min(sum ice,sum fire)$

    然后不难发现 $sum ice$ 是随温度单调不减的,$sum fire$ 是随温度单调不增的

    那么显然答案应该是两者图像的交点,但是严格来说这不是曲线而是离散的点,所以没有确切交点

    那么问题转化为找到一个最大的 $x$ 有 $sum_{ice_ileq x} ice_i leq sum_{fire_i>x} fire_i$ 或者最小的 $x$ 有 $sum_{ice_ileq x} ice_i > sum_{fire_i>x} fire_i$

    其中第二种找到这个 $x$ 后需要找到等效的最大的 $y$ 满足 $sum_{fire_i>x} fire_i leq sum_{fire_i>y} fire_i $ (因为要求能量值最大的情况下温度最高)

    不难想到线段树二分,但是常数过大会T

    我们可以用两个树状数组维护 $sum ice$ $sum fire$,然后运用它lowbit的神奇性质

    因为 $t[x]$ 储存的数据就是 $x-lowbit(x)+1~x$ 这段的数据,也就是说当我们想从一个 $x$ 跳到 $x+2^j (2^j<x且!(2^j|x))$ 时,$t[x+2^j]$ 储存的数据就是我们跳过的那段数据

    所以我们可以利用倍增的思想在树状数组上跳跃,这样就可以用 $O(nlogn)$ 的时间通过此题

    代码

    #include <iostream> 
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #define lowbit(x) (x&-x)
    using namespace std;
    const int N=2e6+10;
    int q,m,tp[N],x[N],y[N],a[N],b[N],t[2][N],fsum;
    
    void Add(int id,int x,int k) {for (;x<=b[0];x+=lowbit(x)) t[id][x]+=k;}
    
    int Query(int id,int x) {if (x<=0||x==b[0]+1) return 0;int ans=0;for (;x;x-=lowbit(x)) ans+=t[id][x];return ans;}
    
    int main() {
        scanf("%d",&q);
        for (int i=1,ord;i<=q;i++) {
            scanf("%d%d",&ord,&tp[i]);
            if (ord==1) scanf("%d%d",&x[i],&y[i]),b[++b[0]]=x[i];
        }
        sort(b+1,b+b[0]+1);b[0]=unique(b+1,b+b[0]+1)-b-1;
        m=log2(b[0]);m=1<<m;
        for (int i=1;i<=q;i++) {
            if (x[i]) {
                x[i]=lower_bound(b+1,b+b[0]+1,x[i])-b;
                Add(tp[i],x[i],y[i]);
                if (tp[i]) fsum+=y[i],a[x[i]]+=y[i];
            }
            else {
                Add(tp[tp[i]],x[tp[i]],-y[tp[i]]);
                if (tp[tp[i]]) fsum-=y[tp[i]],a[x[tp[i]]]-=y[tp[i]];
            }
            int k=0,ice=0,fire=fsum;
            for (int j=m;j;j>>=1)
                if (k+j<=b[0]&&ice+t[0][k+j]<=fire-t[1][k+j]+a[k+j]) ice+=t[0][k+j],fire-=t[1][k+j],k+=j;
            int ans1=ice,ans2=fire;
            if (!max(ans1,ans2)) {printf("Peace
    ");continue;}
            if (ans1>ans2) printf("%d %lld
    ",b[k],2ll*ans1);
            else {
                fire=fsum;k=0;
                for (int j=m;j;j>>=1)
                    if ((k|j)!=k&&k+j<=b[0]&&ans2<=fire-t[1][k+j]+a[k+j]) fire-=t[1][k+j],k+=j;
                printf("%d %lld
    ",b[k],2ll*ans2);
            }
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    34.初识搜索引擎及timeout机制
    33.bulk json格式的理解
    32.es读请示内部分发原理
    31.分片和复制带来的副本一致性
    30.es增删改内部分发原理
    29.es路由原理
    27.初识分布式文档存储系统慨念
    26.bulk批量操作
    26.mget批量查询
    25.partial update内置乐观锁并发控制
  • 原文地址:https://www.cnblogs.com/mastervan/p/14586024.html
Copyright © 2011-2022 走看看