者坏破线阵

前言

如果只想暴力那就只能是暴力分。

题目

众所周知啊,炉石传说有一张卡叫做 阵线破坏者,配合 蜂群来袭大地之鳞 可以玩千甲德恶心对手,但是千甲德跟这道题一点关系都没有。

现在有一个随从叫做 者坏破线阵,在攻击时具有免疫,当其超杀时,可以获得击杀随从的攻击力,在一局游戏开始时,你会获得一个 者坏破线阵 和一个你想要达到的攻击力,作为一个精益求精的玩家,你当然不会打出任何伏笔操作。

这里的伏笔操作指鼠标耐久伏笔,因为每次攻击需要消耗1点鼠标耐久,所以你需要用最少的鼠标耐久来达到你的目的。

现在初始时酒馆里有 (N) 个随从,每个随从的攻击力和血量都是 (a_i),随着游戏进行,接下来会有 (Q) 个事件。

  • (1 S K),表示你新开了一局游戏,拥有一个初始攻击力为 (S)者坏破线阵,询问是否可以通过超杀其它随从来使得其攻击达到 (K),如果可以,输出鼠标耐久的最小花费,如果不能,输出 (-1)
  • (2 W) 表示一个攻击力和血量都是 (W) 的随从加入酒馆。
  • (3 W) 表示一个攻击力和血量都是 (W) 的随从离开酒馆。

每局游戏开始时,随从都会重新刷新。

(1le Nle 3 imes 10^5;1le Qle 10^5;1le Wle 10^{12};1le S,Kle 10^{18}.)

什么是超杀:公鸡大鱼怪。

样例输入
4
1 4 8 1
15
1 2 3
1 2 4
1 2 5
1 3 3
1 3 5
1 3 16
1 4 16
1 8 17
1 100 101
1 100 115
1 3 9
2 2
1 3 9
3 4
1 3 9
样例输出
1
2
-1
0
2
4
3
2
1
-1
3
2
-1

讲解

首先我们有个暴力思路就是每次打攻击力最高且能够超杀的随从,时间复杂度大概是 (O(QNlog_2N))

冷静下来分析,发现我们能够超杀的随从如果不变,我们其实可以一次性多打几个,直到可以增加一个能够超杀的随从为止,这个过程可以在权值线段树上二分解决。

由于我们不能够超杀的随从的属性值一定是不低于我们当前的属性值的,而且我们一旦有新的随从可以超杀,一定优先超杀它,可以发现,这个过程中我们的属性值至少都翻了一倍。

所以这其实是一个类似于倍增的做法。

每局游戏记录一下权值线段树有哪些点被改过,改回去就好了。

时间复杂度 (O(Nlog_2W+Qlog_2Klog_2W).)

需要大力卡常,我用到的卡常方法:

  • Ofast
  • 初始用Build函数建树而不是用Add函数一个一个加
  • putchar输出
  • fread读入

其实蛮好卡的嘛。

代码

卡大常
//12252024832524
#pragma GCC optimize("Ofast")
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 400005;
const LL N = 1e12;
const LL INF = 1ll << 60;
int n;
LL S,a[MAXN];
multiset<LL> fs;

char buf[1<<21];
char getChar(){
	static char *S = buf, *T = S;
	if(S == T) S = buf, T = S + fread(S,1,1<<21,stdin);
	return *(S ++);
}
LL Read()
{
	LL x = 0,f = 1; char c = getChar();
	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getChar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getChar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

#define lc (t[x].l)
#define rc (t[x].r)
int tot,rt;
struct node
{
	int l,r,cnt; LL s;
}t[MAXN*50];
void up(int x){t[x].s = t[lc].s + t[rc].s;t[x].cnt = t[lc].cnt+t[rc].cnt;}
void Add(int &x,LL l,LL r,LL pos,int f)
{
	if(!x) x = ++tot;
	if(l == r) {t[x].s += pos*f;t[x].cnt += f;return;}
	LL mid = (l+r) >> 1;
	if(pos <= mid) Add(lc,l,mid,pos,f);
	else Add(rc,mid+1,r,pos,f);
	up(x); 
}
int now = 1;
void Build(int &x,LL l,LL r)
{
	if(!x) x = ++tot;
	if(l == r)
	{
		while(now <= n && a[now] == l) ++now,++t[x].cnt,t[x].s += l;
		return;
	}
	LL mid = (l+r) >> 1;
	if(now <= n && a[now] <= mid) Build(lc,l,mid);
	if(mid < a[now] && now <= n && a[now] <= r) Build(rc,mid+1,r);
	up(x);
}
int X[MAXN],ans,tl,CNT[MAXN];
LL SS[MAXN];
bool vis[MAXN*50];
LL Query(int x,LL l,LL r,LL ql,LL qr,LL v)
{
	if(ql > qr || !x || !t[x].cnt || v <= 0) return 0;
	if(!vis[x])
	{
		vis[x] = 1;
		CNT[++tl] = t[x].cnt;
		SS[tl] = t[x].s;
		X[tl] = x;
	}
	if(ql <= l && r <= qr && t[x].s <= v) //eat!
	{
		ans += t[x].cnt;
		t[x].cnt = 0;
		LL ret = t[x].s; t[x].s = 0;
		return ret;
	}
	if(l == r)
	{
		int c = Min(0ll+t[x].cnt,(v+l-1)/l);
		ans += c;
		t[x].cnt -= c;
		t[x].s -= c*l;
		return c*l;
	}
	LL mid = (l+r) >> 1,ret = 0;
	if(mid+1 <= qr) ret = Query(rc,mid+1,r,ql,qr,v),v -= ret;
	if(ql <= mid) ret += Query(lc,l,mid,ql,qr,v);
	up(x);
	return ret;
}

int main()
{
	freopen("fish.in","r",stdin);
	freopen("fish.out","w",stdout);
	n = Read();
	for(int i = 1;i <= n;++ i)
	{
		a[i] = Read(); S += a[i];
		fs.insert(a[i]);
	}
	fs.insert(INF);
	sort(a+1,a+n+1);
	Build(rt,1,N);
	for(int Q = Read(); Q ;-- Q)
	{
		int opt = Read(); LL val = Read();
		if(opt == 1)
		{
			LL nd = Read(); ans = 0;
			if(val+S < nd){putchar('-');putchar('1');putchar('
');continue;}
			if(val >= nd){putchar('0');putchar('
');continue;}
			while(1)
			{
				multiset<LL>::iterator cant = fs.lower_bound(val);
				val += Query(rt,1,N,1,val-1,Min(nd,*cant+1)-val);
				if(val >= nd) break;
				else if(val <= *cant) {ans = -1;break;}
			}
			Put(ans,'
');
			for(int i = tl;i >= 1;-- i)
			{
				vis[X[i]] = 0;
				t[X[i]].cnt = CNT[i];
				t[X[i]].s = SS[i];
			}
			tl = 0;
		}
		else if(opt == 2) Add(rt,1,N,val,1),S += val,fs.insert(val);
		else Add(rt,1,N,val,-1),S -= val,fs.erase(fs.lower_bound(val));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/15376391.html