zoukankan      html  css  js  c++  java
  • [省选联考 2020 A/B 卷] 冰火战士(数据结构)

    opening

    题目链接

    来做做去年的省选题,T1确实是个馺嬖题,不过想出不卡常的正解还是比较难的。

    outline

    一场比赛即将开始。

    每位战士有两个属性:温度和能量,有两派战士:冰系战士的技能会对周围造成降温冰冻伤害,因而要求场地温度不低于他的自身温度才能参赛;火系战士的技能会对周围造成升温灼烧伤害,因而要求场地温度不高于他的自身温度才能参赛。

    当场地温度确定时,双方能够参赛的战士分别排成一队。冰系战士按自身温度从低到高排序,火系战士按自身温度从高到低排序,温度相同时能量大的战士排在前面。首先,双方的第一位战士之间展开战斗,两位战士消耗相同的能量,能量少的战士将耗尽能量退出比赛,而能量有剩余的战士将继续和对方的下一位战士战斗(能量都耗尽则双方下一位战士之间展开战斗)。如此循环,直至某方战士队列为空,比赛结束。

    你需要寻找最佳场地温度:使冰火双方消耗总能量最高的温度的最高值。

    现在,比赛还处于报名阶段,目前还没有任何战士报名,接下来你将不断地收到报名信息和撤回信息。其中,报名信息包含报名战士的派系和两个属性,撤回信息包含要撤回的报名信息的序号。每当报名情况发生变化(即收到一条信息)时,你需要立即报出当前局面下的最佳场地温度,以及该场地温度下双方消耗的总能量之和是多少。若当前局面下无论何种温度都无法开展比赛(某一方没有战士能参赛),则只要输出 Peace。

    数据范围 (2e6)

    solution

    确实看上去题目挺复杂,不过随便转化一下发现挺三分的,不过不知道符合不符合条件,不过再一想发现可以用线段树维护单点值,然后直接二分就可以,复杂度 (Theta(nlog^2n))

    感觉只能拿60分,不过听神犇 (thesure) 说,改成树状数组再卡卡常就A了,不过听说 神犇中的神犇 (lin4xu) 直接线段树 A了,令人%%%。

    回到这道题,发现需要一个 (nlog n) 的算法,于是你的线段树的每个叶子节点表示前缀和,然后就可以线段树上二分了,复杂度 (nlog n),不过因为常数过大,所以跑不过去,但

    是如果你会树状数组上二分的话或者zkw线段树,那么你就A了它,所以这道题就完了,我在下面说一下树状数组二分的注意事项。

    std

    // by longdie 
    #include <bits/stdc++.h> 
    #define ll long long 
    #define ull unsigned long long 
    #define rint register int
    using namespace std; 
    inline int read(int s = 0, int f = 1, char ch = getchar()) {
    	while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } 
    	while(isdigit(ch)) { s = s*10 + ch - '0', ch = getchar(); } 
    	return s * f; 
    }
    const int N = 2e6 + 5; 
    int m, b[N], tot, c1[N], c2[N], sum; 
    struct Q {
    	int op, id, x, y; 
    } q[N]; 
    inline int lowbit(int x) { return x & -x; }
    inline void add(int x, int y, int *c) {
    	for(; x <= tot; x += lowbit(x)) c[x] += y; 
    }
    inline int get(int x, int *c, int res = 0) {
    	for(; x; x -= lowbit(x)) res += c[x]; 
    	return res; 
    }
    inline void change(int id, int t, int val) {
    	if(!id) add(t, val, c1); 
    	else add(t, val, c2), sum += val; 
    }
    inline void query() {
    	int pos = 0, res1 = 0, res2 = 0, ans = 0, p = 0; 
    	for(rint j = 20, x; j >= 0; --j) {
    		x = pos + (1 << j); 
    		if(x > tot) continue; 
    		int tmp1 = res1 + c1[x], tmp2 = res2 + c2[x]; 
    		if(tmp1 <= sum - tmp2) res1 = tmp1, res2 = tmp2, pos = x; 
    	}
    	ans = min(res1, sum - res2), p = pos; 
    	++pos; 
    	int flag = 0; 
    	res1 = get(pos, c1), res2 = sum - get(pos, c2);
    	if(min(res1, res2) >= ans) ans = min(res1, res2), p = pos, flag = 1; 
    	if(flag) {
    		pos = 0, res1 = res2 = 0; 
    		for(rint j = 20; j >= 0; --j) {
    			int x = pos + (1 << j); 
    			if(x > tot) continue; 
    			int tmp1 = res1 + c1[x], tmp2 = res2 + c2[x]; 
    			if(x <= p) { pos = x, res1 = tmp1, res2 = tmp2; continue; }
    			if(min(tmp1, sum-tmp2) >= ans) { 
    				pos = x, res1 = tmp1, res2 = tmp2; continue; 
    			}
    		}
    		p = pos; 
    	}
    	if(ans == 0) puts("Peace");
    	else printf("%d %d
    ", b[p+1]-1, ans*2); 
    }
    signed main() {
    	m = read(); 
    	for(rint i = 1; i <= m; ++i) {
    		q[i].op = read(); 
    		if(q[i].op == 2) q[i].x = read(); 
    		else q[i].id = read(), q[i].x = read() + (q[i].id == 1), q[i].y = read(), b[++tot] = q[i].x; 
    	}
    	sort(b + 1, b + tot + 1), tot = unique(b + 1, b + tot + 1) - b - 1;
    	for(rint i = 1; i <= m; ++i) {
    		if(q[i].op == 1) {
    			q[i].x = lower_bound(b + 1, b + tot + 1, q[i].x) - b;
    			change(q[i].id, q[i].x, q[i].y);
    		}
    		else {
    			int k = q[i].x; change(q[k].id, q[k].x, -q[k].y);
    		}
    		query();
    	}
    	return 0; 
    }
    

    end

    树状数组上二分,就是从大到小开始跳就可以了,其实就是个二分了。

  • 相关阅读:
    最大子数组求和并进行条件组合覆盖测试
    Ubuntu 16.04 c++ Google框架单元测试
    The directory '/home/stone/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If execu
    Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/cache/app-info -a -e /usr/bin/appstreamcli; then appstreamcli refresh > /dev/null; fi'
    个人博客作业三:微软小娜APP的案例分析
    补交 作业一
    补交 作业二:个人博客作业内容:需求分析
    嵌入式软件设计第12次实验报告
    嵌入式软件设计第11次实验报告
    嵌入式软件设计第10次实验报告
  • 原文地址:https://www.cnblogs.com/longdie/p/14607841.html
Copyright © 2011-2022 走看看