1. 程式人生 > 其它 >noip模擬測試34

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;
}