noip模拟测试34

这次考试,全靠第一题撑着了,第一题我画了画图,就看出了二分答案,然后差不多半个小时就码的差不多了,又加上了一点小优化,但是没拿到满分,失误有两点,1.二分之前没有特判0的情况 2.这属于一个知识性问题,我当时不知道,因为快排带log,所以我们可以使用一个 nth_element()取出序列前m大。然后是T2,虽然题面看起来像是一个高斯消元,但是结合数据范围,我就知道事情没有辣么简单,高斯消元一次就是n^3, 显然过不去,但是,我当时注意到了每次之需要求出 x1,但是没想到把所有变量都用 x1 表示(我太菜了),最后是T3,我当时一直在想一条直线扫过来扫过去,但是我不知道如何实现,想了半天只能打个暴力,还打假了。这次要没有T1,估计又要保龄了。。。

T1 Merchant

思路:画个图,因为每个物品的价值都是一个一次函数,所以显然具有决策单调性,我们可以进行二分答案,但是由于我们需要取出序列前m大,可以使用nth_element() O(N),求出,但是,这东西只能保证将序列前 m 小的东西放在前 m 位,但不保证是有序的,所以在计算过程中我们需要特判,如果小于0就选择不放。
代码如下:

AC_code
#include<bits/stdc++.h>
#define int long long
#define re register int
#define ii inline int
#define iv inline void
using namespace std;
const int N=1e6+10;
struct node
{
	int k,b;
}use[N];
int n,m,s;
ii read()
{
	int x=0;
	bool 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);
}
inline bool check(int x)
{
	int cnt=0,sum=0;
	int q[N];
	for(re i=1;i<=n;i++)
		q[i]=((use[i].k*x+use[i].b)*-1);
	nth_element(q+1,q+m+1,q+n+1);
	for(re i=1;i<=m;i++)
	{
		if(sum>=s)
			break;
		if(q[i]<0)
			sum-=q[i];
	}
	return sum>=s;
}
ii my(node a,node b)
{
	if(a.k!=b.k)
		return a.k>b.k;
	return a.b>b.b;
}
signed main()
{
	n=read();
	m=read();
	s=read();
	bool fu=1,zh=1;
	for(re i=1;i<=n;i++)
	{
		use[i].k=read();
		use[i].b=read();
		if(use[i].k>0)
			fu=0;
		if(use[i].k<0)
			zh=0;
	}
	sort(use+1,use+n+1,my);	
	if(check(0))
	{
		printf("0\n");
		return 0;
	}
	int l=0,r=1e9+10,out=r,out2=r;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		{
			out=mid;
			r=mid-1;
		}
		else
			l=mid+1;
	}
	printf("%lld\n",out);
	return 0;
}

T2 Equation

思路:看到这种数据范围,显然是nlogn,所以我们考虑使用线段树,显然,我们可以将每个变量表示成 \(x_i=k_i+x_1\)\(x_i=k_i-x_1\) 的形式,那么对于询问 u,v,t ,将表示 u 和 v的式子加起来,只会存在如下几种情况,
1.\(x_u+x_v=t\),只需要判断等式是否成立.
2.\(x_u+x_v=t-2\times x_1\)
3.\(x_u+x_v=t+2\times x_1\)
那么这就是一个区间修改,单点查询的操作,我们可以使用线段树或者树状数组实现,我使用了线段树,我们在线段树上只需要保存三个东西,自己的权值(sum),两个延迟标记(lazy),由于修改的时候对于深度为奇偶的点影响不同,所以这两个延迟标记数组一个是奇加偶减,另一个是偶加奇减,还要注意在每次 change 的时候都要判断当前的深度奇偶性!!
代码如下:

AC_code
#include<bits/stdc++.h>
#define re register int
#define ii inline int
#define iv inline void
#define lc (rt<<1)
#define rc (rt<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N=1e6+10;
int n,q,tot,timi;
int to[N<<1],next[N<<1],val[N<<1],head[N];
int size[N],deep[N],id[N],dp[N],zh[N],ifs[N],fw[N];
ii read()
{
	int x=0;
	bool 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
{
	int sum[N<<2],lazy1[N<<2],lazy2[N<<2];
	iv updata_1(int p,int l,int r,int w)
	{
		if(l==r)
		{
			if(deep[ifs[l]])
				sum[p]+=w;
			else
				sum[p]-=w;	
			return;
		}
		lazy1[p]+=w;
	}
	iv updata_2(int p,int l,int r,int w)
	{
		if(l==r)
		{
			if(deep[ifs[l]])
				sum[p]-=w;
			else
				sum[p]+=w;
			return;
		}
		lazy2[p]+=w;
	}
	iv pd(int rt,int l,int r)
	{
		if(lazy1[rt])
		{
			updata_1(lc,l,mid,lazy1[rt]);
			updata_1(rc,mid+1,r,lazy1[rt]);
			lazy1[rt]=0;
		}
		if(lazy2[rt])
		{
			updata_2(lc,l,mid,lazy2[rt]);
			updata_2(rc,mid+1,r,lazy2[rt]);
			lazy2[rt]=0;
		}
	}
	iv build(int rt,int l,int r)
	{
		if(l==r)
		{
			sum[rt]=zh[l];
			return;
		}
		build(lc,l,mid);
		build(rc,mid+1,r);
	}
	inline long long query(int rt,int l,int r,int p)
	{
		if(l==r)
			return sum[rt];
		pd(rt,l,r);
		if(mid>=p)
			return query(lc,l,mid,p);
		return query(rc,mid+1,r,p);
	}
	iv insert_1(int rt,int l,int r,int L,int R,int z)
	{
		if(L>R)
			return;
		if(L<=l&&r<=R)
		{
			if(l==r)
			{
				if(deep[ifs[l]])
					sum[rt]+=z;
				else
					sum[rt]-=z;
				return;
			}
			lazy1[rt]+=z;
			return;
		}
		pd(rt,l,r);
		if(mid>=L)
			insert_1(lc,l,mid,L,R,z);
		if(mid<R)
			insert_1(rc,mid+1,r,L,R,z);
	}
	iv insert_2(int rt,int l,int r,int L,int R,int z)
	{
		if(L>R)
			return;
		if(L<=l&&r<=R)
		{
			if(l==r)
			{
				if(deep[ifs[l]])
					sum[rt]-=z;
				else
					sum[rt]+=z;
				return;
			}
			lazy2[rt]+=z;
			return;
		}
		pd(rt,l,r);
		if(mid>=L)
			insert_2(lc,l,mid,L,R,z);
		if(mid<R)
			insert_2(rc,mid+1,r,L,R,z);
	}
}T;
iv add(int x,int y,int w)
{
	to[++tot]=y;
	next[tot]=head[x];
	head[x]=tot;
	val[tot]=w;
}
iv dfs(int st,int f)
{
	deep[st]=deep[f]^1;
	size[st]=1;
	id[st]=++timi;
	ifs[timi]=st;
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		dfs(p,st);
		size[st]+=size[p];
	}
}
iv dfs2(int st,int f)
{
	for(re i=head[st];i;i=next[i])
	{
		int p=to[i];
		zh[id[p]]=val[i]-zh[id[st]];
		dfs2(p,st);
	}
}
signed main()
{
	n=read();
	q=read();
	int f,w,opt,u,v;
	long long ans1,ans2,s;
	for(re i=2;i<=n;i++)
	{
		f=read();
		w=read();
		fw[i]=w;
		add(f,i,w);
	}
	dfs(1,0);
	dfs2(1,0);
	T.build(1,1,n);
	while(q--)
	{
		opt=read();
		if(opt==1)
		{
			u=read();
			v=read();
			s=read();
			ans1=T.query(1,1,n,id[u]);
			ans2=T.query(1,1,n,id[v]);;
			if(deep[u]!=deep[v])
			{
				if(ans1+ans2!=s)
					printf("none\n");
				else
					printf("inf\n");
			}
			else
			{
				if(deep[u]==0)
				{
					if(!((ans1+ans2-s)&1))
						printf("%d\n",(ans1+ans2-s)/2);
					else
						printf("none\n");
				}
				else
				{
					if(!((s-ans1-ans2)&1))
						printf("%d\n",(s-ans1-ans2)/2);
					else
						printf("none\n");
				}
			}
		}	
		else
		{	
			u=read();
			w=read();
			int tmp=w;
			w=w-fw[u];
			if(deep[u])
				T.insert_1(1,1,n,id[u],id[u]+size[u]-1,w);
			else
				T.insert_2(1,1,n,id[u],id[u]+size[u]-1,w);
			fw[u]=tmp;
		}
	}	
	return 0;
}

posted @ 2021-08-11 18:41  WindZR  阅读(58)  评论(0编辑  收藏  举报