ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HNOI 2014-2017 泛做

2022-01-23 15:34:48  阅读:138  来源: 互联网

标签:rt ch return int HNOI fa 2014 2017 include


可以催更,但是不保证更

2017 大佬

题目描述

点此看题

解法

关于虽然评分是黑但是我还是感觉好水并且还是要写题解这件事

观察发现存活和攻击是两件独立的事,所以对于最优方案我们只需要求出在保证存活的情况下能拿去攻击的最大天数,这可以用一个简单的背包解决。

在判断能否击败大佬的时候,我们可以考虑把两个大招拆分,对于一次大招我们可以用一个三元组来表示:(day,F,L),考虑到最多只有 \(100\) 天,所以 \(F\) 的取值应该不会很多。那么我们可以暴力 \(\tt bfs\) 出所有的三元组,但是 \(\tt hash\) 的时候只用保留 (F,L),天数取最小的一定最优。

然后考虑找出两个大招来拼凑出最优解,考虑不会让大佬血量低于 \(0\) 并且最后能击败的条件是:

\[F_1+F_2\leq c_i\ \and \ c_i-F_1-F_2\leq MaxDay-day_1-day_2 \]

那么第一个条件可以双指针,维护最小的 \(day_2-F_2\) 来保证第二个条件。还有一些情况是不使用大招或者只使用一次大招,由于过于简单在此不必赘述。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
const int M = 1005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,mc,up,Day,a[M],b[M],c[M],dp[M][M];
struct node{int d,f,l;};map<pair<int,int>,int> mp;
struct shit
{
	int x,y;
	bool operator < (const shit &b) const
	{return y<b.y;}
}s[10000005];
void bfs()
{
	queue<node> q;q.push(node{1,1,0});
	while(!q.empty())
	{
		node u=q.front();q.pop();
		if(u.d==Day) continue;
		q.push(node{u.d+1,u.f,u.l+1});
		long long t=1ll*u.f*u.l;
		if(u.l>1 && t<=up && !mp.count(make_pair(t,u.l)))
		{
			mp[make_pair(t,u.l)]=1;s[++k]=shit{u.d+1,t};
			q.push(node{u.d+1,t,u.l});
		}
	}
}
signed main()
{
	n=read();m=read();mc=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) b[i]=read();
	for(int i=1;i<=m;i++) up=max(up,c[i]=read());
	for(int i=1;i<=n;i++)
		for(int j=a[i];j<=mc;j++)
		{
			int id=min(j-a[i]+b[i],mc);
			dp[i][j-a[i]]=max(dp[i][j-a[i]],dp[i-1][j]+1);
			dp[i][id]=max(dp[i][id],dp[i-1][j]);
		}
	for(int i=1;i<=n;i++)
		for(int j=0;j<=mc;j++)
			Day=max(Day,dp[i][j]);
	bfs();sort(s+1,s+1+k);
	for(int i=1;i<=m;i++)
	{
		if(c[i]<=Day) {puts("1");continue;}
		int fl=0,mn=0;
		for(int j=k,p=1;j>=1;j--)
		{
			while(p<=k && s[j].y+s[p].y<=c[i])
				mn=min(mn,s[p].x-s[p].y),p++;
			if(s[j].y<=c[i] && mn+c[i]-s[j].y<=Day-s[j].x)
				{fl=1;break;}
		}
		printf("%d\n",fl);
	}
}

2017 单旋

题目描述

点此看题

解法

重要的观察:本题的旋转到根操作只涉及最大值和最小值,最值的旋转肯定存在某种性质。

反复手玩发现,最小值的旋转就是把它的右子树接到父亲上,然后直接把整棵树当成它的右儿子,所以父子关系和深度的变化是很少的,最大值的旋转方式类似。

所以我们拿个 \(\tt set\) 找前驱后继,用于插入;拿个单点查询、区间修改的线段树维护深度。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int M = 100005;
#define sit set<int>::iterator
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
void write(int x)
{
	if(x>=10) write(x/10);
	putchar(x%10+'0');
}
int n,m,a[M],b[M],c[M];
//namespace segment-tree
int ad[M<<2],tr[M<<2];
void down(int i)
{
	if(!ad[i]) return ;
	tr[i<<1]+=ad[i];ad[i<<1]+=ad[i];
	tr[i<<1|1]+=ad[i];ad[i<<1|1]+=ad[i];
	ad[i]=0;
}
void add(int i,int l,int r,int L,int R,int c)
{
	if(l>R || L>r) return ;
	if(L<=l && r<=R) {tr[i]+=c;ad[i]+=c;return ;}
	int mid=(l+r)>>1;down(i);
	add(i<<1,l,mid,L,R,c);
	add(i<<1|1,mid+1,r,L,R,c);
	tr[i]=tr[i<<1]+tr[i<<1|1]; 
}
void ins(int i,int l,int r,int id,int c)
{
	if(l==r) {tr[i]=c;return ;}
	int mid=(l+r)>>1;down(i);
	if(mid>=id) ins(i<<1,l,mid,id,c);
	else ins(i<<1|1,mid+1,r,id,c);
	tr[i]=tr[i<<1]+tr[i<<1|1];
}
int ask(int i,int l,int r,int id)
{
	if(l==r) return tr[i];
	int mid=(l+r)>>1;down(i);
	if(mid>=id) return ask(i<<1,l,mid,id);
	return ask(i<<1|1,mid+1,r,id);
}
//using set to maintain spaly
set<int> s;int rt,fa[M],ch[M][2];
int fuck(int x)
{
	if(!rt) {rt=x;s.insert(x);ins(1,1,n,x,1);return 1;}
	sit it=s.lower_bound(x);int ans=0;
	if(it!=s.end() && !ch[*it][0])
	{
		ch[*it][0]=x;fa[x]=*it;
		ins(1,1,n,x,ans=ask(1,1,n,*it)+1);
		s.insert(x);return ans;
	}
	it--;ch[*it][1]=x;fa[x]=*it;
	ins(1,1,n,x,ans=ask(1,1,n,*it)+1);
	s.insert(x);return ans;
}
int spmin()
{
	int v=*s.begin();
	if(v==rt) return 1;
	int d=ask(1,1,n,v);
	ins(1,1,n,v,1);add(1,1,n,fa[v],m,1);
	ch[fa[v]][0]=ch[v][1];fa[ch[v][1]]=fa[v];
	fa[v]=0;ch[v][1]=rt;fa[rt]=v;rt=v;return d;
}
int spmax()
{
	int v=*s.rbegin();
	if(v==rt) return 1;
	int d=ask(1,1,n,v);
	ins(1,1,n,v,1);add(1,1,n,1,fa[v],1);
	ch[fa[v]][1]=ch[v][0];fa[ch[v][0]]=fa[v];
	fa[v]=0;ch[v][0]=rt;fa[rt]=v;rt=v;return d;
}
int delmin()
{
	int d=spmin();s.erase(rt);
	int tmp=rt;rt=ch[tmp][1];ch[tmp][1]=0;
	add(1,1,n,1,n,-1);return d;
}
int delmax()
{
	int d=spmax();s.erase(rt);
	int tmp=rt;rt=ch[tmp][0];ch[tmp][0]=0;
	add(1,1,n,1,n,-1);return d;
}
signed main()
{
	m=read();
	for(int i=1;i<=m;i++)
	{
		a[i]=read();
		if(a[i]==1) c[++n]=b[i]=read();
	}
	sort(c+1,c+1+n);n=unique(c+1,c+1+n)-c-1;
	for(int i=1;i<=m;i++) if(a[i]==1)
		b[i]=lower_bound(c+1,c+1+n,b[i])-c;
	for(int i=1;i<=m;i++)
	{
		if(a[i]==1) write(fuck(b[i]));
		if(a[i]==2) write(spmin());
		if(a[i]==3) write(spmax());
		if(a[i]==4) write(delmin());
		if(a[i]==5) write(delmax());
		puts("");
	}
}

标签:rt,ch,return,int,HNOI,fa,2014,2017,include
来源: https://www.cnblogs.com/C202044zxy/p/15836466.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有