noip模拟测试22

考试总结:这次考试题,有好多部分分,导致了我在考试过程中一心想拿到这些部分分,对于正解没有留出时间进行思考,这是一个教训,在以后的考试中我一定要留出足够的思考时间,不要被部分分限制。还有,我的部分分也没有拿满,犯了一些zz的错误,有因为数组开小的,还有没有控制好优先级的(对于特殊性质的特殊解法),还有自己没有验证正确性的一些暴力优化,还遇到了一个因为我懒,没去学的知识点(痛失20分)。总体来说,这次考试我暴露出的问题有许多,在以后的考试中我会进行改正。

T1 d

思路:很显然,我们要求矩形并起来的最大值,就要去掉最多的 x,y,最小的矩形,那么我们可以将 x,预处理排序v,同时用一个优先队列维护 y ,这样我们刚开始假设去掉 m 个 x,接着我们不断将 x 放回,并去掉 y 更新答案即可。
代码如下:

AC_Code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define lc rt<<1
#define rc rt<<1|1
#define mid ((l+r)>>1)
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=1e5+10;
const int INF=1e9+10;
int t,n,m,ans;
struct C1
{
	int a,pos;
}u1[N];
struct C2
{
	int b,pos;
	friend bool operator < (C2 x,C2 y)
	{
		return x.b>y.b;
	}
}u2[N];
priority_queue<C2> q;
bool vis[N],v2[N];
ii my1(C1 a,C1 b)
{
	return a.a<b.a;
}
ii read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=0;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return (f)?x:(-x);
}
signed main()
{
	t=read();
	long long minn_a,minn_b;
	if(t==0)
		return 0;
	while(t--)
	{
		n=read();
		m=read();
		ans=0;
		minn_a=INF;
		minn_b=INF;
		for(re i=1;i<=n;i++)
		{
			u1[i].a=read();
			u2[i].b=read();
			u1[i].pos=u2[i].pos=i;
		}
		sort(u1+1,u1+n+1,my1);
		memset(vis,0,sizeof(vis));
		memset(v2,0,sizeof(v2));
		while(!q.empty())
			q.pop();
		for(re i=1;i<=m;i++)
			vis[u1[i].pos]=1;
		for(re i=m+1;i<=n;i++)
			q.push((C2){u2[u1[i].pos].b,u1[i].pos});
		ans=u1[m+1].a*q.top().b;
		for(re i=m;i;i--)
		{
			vis[u1[i].pos]=0;
			minn_a=u1[i].a;
			q.push((C2){u2[u1[i].pos].b,u1[i].pos});
			v2[q.top().pos]=1;
			q.pop();
			minn_b=q.top().b;
			if(v2[u1[i].pos])
				continue;
			ans=max(ans,minn_a*minn_b);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

T2 e

思路:很显然,我们需要一种可以维护一条链上信息的数据结构,主席树,那么我们只需要求出所有点的lca,然后分别以这两个点对应的树求出 r 对应的rank,那么我们再通过查询树中 排名为 (rank-1),(rank),(rank+1)的数值进行计算,最后取min即可,注意,在查询的时候有一些细节,当 rank,rank-1,rank+1,<=0或 >sum[lca]-sum[p]的时候我们就不能进行查询,具体实现见代码:
(因为我们要找的是小于r的最大值和大于r的最小值,所以还有另一种打法 hzoi-fengwu

AC_Code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
#define mid ((l+r)>>1)
using namespace std;
const int N=5e5+10;
const int INF=1e9+10;
vector<int> v[N];
int n,q,type,tot,timi,r,ans,k,cnt,jk;
int a[N],to[N<<1],next[N<<1],head[N],cun_k[N],lsh[N<<4],rt[N],cun_r[N];
int deep[N],son[N],size[N],num[N],zh[N],fa[N],top[N];
struct CUN
{
	int ls,rs,sum;
}use[N*80];
ii read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=0;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return (f)?x:(-x);
}
struct Segment_Tree
{
	ii insert(int now,int l,int r,int zh)
	{
		int p=++jk;
		use[p]=use[now];
		if(l==r)
		{
			use[p].sum++;
			return p;
		}
		if(mid>=zh)
			use[p].ls=insert(use[now].ls,l,mid,zh);
		else
			use[p].rs=insert(use[now].rs,mid+1,r,zh);
		use[p].sum=use[use[p].ls].sum+use[use[p].rs].sum;
		return p;
	}
	ii gett(int x,int y)
	{
		int fx=top[x],fy=top[y];
		while(fx!=fy)
		{
			if(deep[fx]<deep[fy])
			{
				swap(fx,fy);
				swap(x,y);
			}
			x=fa[fx];
			fx=top[x];
		}
		return (deep[x]<deep[y])?x:y;
	}
	ii query_rank(int last,int now,int l,int r,int zh)
	{
		if(l==r)
			return 0;
		int sum=use[use[now].ls].sum-use[use[last].ls].sum;
		if(mid>=zh)	return query_rank(use[last].ls,use[now].ls,l,mid,zh);
		return sum+query_rank(use[last].rs,use[now].rs,mid+1,r,zh);
	}
	ii query(int last,int now,int l,int r,int rk)
	{
		if(l==r)
			return l;
		int sum=use[use[now].ls].sum-use[use[last].ls].sum;
		if(sum>=rk)	return query(use[last].ls,use[now].ls,l,mid,rk);
		return query(use[last].rs,use[now].rs,mid+1,r,rk-sum);
	}
}T;
iv add(int x,int y)
{
	to[++tot]=y;
	next[tot]=head[x];
	head[x]=tot;
}
iv dfs(int st,int f)
{
	num[st]=++timi;
	zh[timi]=a[st];
	size[st]=1;
	deep[st]=deep[f]+1;
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		if(p==f)
			continue;
		fa[p]=st;
		dfs(p,st);
		size[st]+=size[p];
		son[st]=(size[son[st]]>size[p])?son[st]:p;
	}
}
iv dfs2(int st,int t)
{
	top[st]=t;
	if(!son[st])
		return;
	dfs2(son[st],t);
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		if(p==fa[st]||p==son[st])
			continue;
		dfs2(p,p);
	}
}
iv dfs3(int st,int f)
{
	rt[st]=T.insert(rt[f],1,cnt,a[st]);
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		if(p==f)
			continue;
		dfs3(p,st);
	}
}
signed main()
{
	n=read();
	q=read();
	type=read();
	for(re i=1;i<=n;i++)
	{
		a[i]=read();
		lsh[++cnt]=a[i];
	}
	for(re i=1,u2,v2;i<n;i++)
	{
		u2=read();
		v2=read();
		add(u2,v2);
		add(v2,u2);
	}
	dfs(1,0);
	dfs2(1,1);
	if(q==0)
		return 0;
	for(re i=1;i<=q;i++)
	{
		cun_r[i]=read();
		lsh[++cnt]=cun_r[i];
		cun_k[i]=read();
		for(re j=1;j<=cun_k[i];j++)
			v[i].push_back(read());
	}
	sort(lsh+1,lsh+cnt+1);
	cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
	for(re i=1;i<=n;i++)
		a[i]=lower_bound(lsh+1,lsh+cnt+1,a[i])-lsh;
	for(re i=1;i<=q;i++)
		cun_r[i]=lower_bound(lsh+1,lsh+cnt+1,cun_r[i])-lsh;
	dfs3(1,0);
	for(re i=1;i<=q;i++)
	{
		int lca,rk;
		v[i][0]=(v[i][0]-1+ans*type)%n+1;
		lca=v[i][0];
		for(re j=1;j<v[i].size();j++)
		{
			v[i][j]=(v[i][j]-1+ans*type)%n+1;
			lca=T.gett(lca,v[i][j]);
		}
		lca=fa[lca];
		ans=INF;
		for(re j=0;j<v[i].size();j++)
		{
			rk=T.query_rank(rt[lca],rt[v[i][j]],1,cnt,cun_r[i]);
			if(rk>=(use[rt[v[i][j]]].sum-use[rt[lca]].sum))	
			ans=min(ans,abs(lsh[T.query(rt[lca],rt[v[i][j]],1,cnt,rk)]-lsh[cun_r[i]]);
			else
			ans=min(ans,abs(lsh[T.query(rt[lca],rt[v[i][j]],1,cnt,rk+1)]-lsh[cun_r[i];
			if(rk-1<=1)
			ans=min(ans,abs(lsh[T.query(rt[lca],rt[v[i][j]],1,cnt,1)]-lsh[cun_r[i]]));
			else	
			ans=min(ans,abs(lsh[T.query(rt[lca],rt[v[i][j]],1,cnt,rk-1)]-lsh[cun_r[i];
			if(rk>=1&&rk<=use[rt[v[i][j]]].sum-use[rt[lca]].sum)
			ans=min(ans,abs(lsh[T.query(rt[lca],rt[v[i][j]],1,cnt,rk)]-lsh[cun_r[i]]);
		}
		printf("%lld\n",ans);
	}
	
	return 0;
}

T3 f

补坑:
树状数组求逆序对,我们对于一个序列倒序枚举,显然,根据逆序对的定义,我们查询的小于当前数的权值的前缀和即为当前点的逆序对个数,注意,我们的树状数组建立在总序列的值域的基础上

    for(re i=1;i<=n;i++)
	{
		a[i]=read()+1;
		maxx=max(a[i],maxx);	
	}
	for(re i=n;i;i--)
	{
		ans+=ask(a[i]-1);
		add(a[i],1);
	}
	cout<<ans<<endl;
原文地址:https://www.cnblogs.com/WindZR/p/15043478.html