noip34

因为改不动T3而来水博客的屑

昨晚没睡好,大致看了一遍题面后,选择了死亡231,然后就死的很惨。

T1

一开始大致看题面的时候,就略了一眼,加上没读全题,啥思路也没有,最后四十分钟滚回来看了看,发现就是个二分,码好后,发现不太对劲,\(O(n\log n)\) 排序会T,然而不知道该怎么改,就直接交了。

没判0挂了8pts

正解:

就是个二分,二分时间,\(check\) 时计算当前时间各个物品的价值,然后排序,取前m个大,从到小累加,比 \(s\) 大返回true,否则false。

二分前先判0是否合法,合法直接输出0,不合法再去二分。

然而\(O(n\log n)\)\(sort\) 会T,发现我们只关心前m大的,所以可以用一个叫 \(nth \_element\) 的东西来排序,具体用法:

nth_element(a+head,a+kth,a+tail);

重排 \([head,tail)\) 中的元素,使得 \(kth\) 所指向的元素为拍完序后的该位置出现的数,新的 \(nth\) 元素前所有的元素小于等于新的 \(nth\) 元素后的所有元素。

然后就有个问题,有负的贡献怎么办? 不选不就好了,那它跟0取个 \(\max\) 再排序即可,因为选负的不如不选。

然后就就没了,难点就在于不认识 \(nth\_ element\)

Code
#include<cstdio>
#include<algorithm>
#define MAX 1000100
#define re register
#define int long long
using std::sort;
using std::nth_element;
namespace OMA
{
	int n,m,s;
	int tmp[MAX];
	int ans = 1e9+7;
	struct node
	{ int k,b; }p[MAX];
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	inline int max(int a,int b)
	{ return a>b?a:b; }
	inline bool cmp(int a,int b)
	{ return a>b; }
	inline bool check(int mid)
	{
		for(re int i=1; i<=n; i++)
		{ tmp[i] = max(0,mid*p[i].k+p[i].b); }
		//sort(tmp+1,tmp+1+n,cmp);
		nth_element(tmp+1,tmp+n-m+1,tmp+n+1);
		//for(re int i=1; i<=n; i++)
		//{ printf("%lld ",tmp[i]); }
		//printf("\n");
		int sum = 0;
		for(re int i=n; i>=n-m+1; i--)
		{
			sum += tmp[i];
			if(sum>=s)
			{ return true; }
		}
		return false;
	}
	signed main()
	{
		//freopen("node.in","r",stdin);
		cin >> n >> m >> s;
		for(re int i=1,k,b; i<=n; i++)
		{ p[i] = (node){(cin >> k,k),(cin>>b,b)}; }
		if(check(0))
		{ printf("0\n"); return 0; }
		int l = 0,r = 1e9;
		while(l<=r)
		{
			int mid = (l+r)>>1;
			//printf("l=%d r=%d mid=%d\n",l,r,mid);
			if(check(mid))
			{ r = mid-1; ans = mid; /*printf("%d %d\n",ans,mid);*/ }
			else
			{ l = mid+1; }
		}
		printf("%lld\n",ans);
		return 0;
	}
}
signed main()
{ return OMA::main(); }

记得判0QAQ

T2

一眼看以为高斯消元,看到数据范围直接去世。

短暂的思考发呆犯困之后,选择21pts的特殊性质。

氵完后,试图再搞搞,然而脑子里已经成了浆糊,就滚去T3了。

赛后发现大家都是86pts

正解:

发现对于每个 \(x\) ,都可以表示成 \(x_{i}=k-x_{1}\) 的形式,其中的 \(k\) 是一些 \(w\) 的加加减减,通过手模就可以找到对应的规律,然后就可以方便的回答询问,

  • 对于操作1,将表示 \(u,v\) 的式子相加,此时会出现两种情况:
  1. \(x_{u}+x_{v}=t\) ,此时只需判断是否 \(s=t\) ,若相等,则\(inf\),否则 \(none\)

  2. \(x_{u}+x_{v}=t\pm x_{1}\) 然后就可以求得 \(x_{1}\) ,注意题目要求 \(x\) 为整数,不符合条件要输出 \(inf\)

  • 对于操作二,发现对于节点 \(u\) 的修改,实际上只会影响到 \(u\) 的子树内的信息。

所以就是个区间修改+单点查询,修改时根据点深度的奇偶对应的乘上 \(\pm1\) 即可。

所以用个树状数组来实现,复杂度 \(O((n+q)\log n)\)

如果用线段树的话,是两个 \(\log\) 的,过不了最后一个子任务,卡nm呢

然而还是有人用线段树过了

注意判断解不是整数的情况,以及答案最后要除以2。

86pts
#include<cstdio>
#define MAX 1000010
#define re register
namespace OMA
{
	int n,q;
	int fa[MAX],w[MAX];
	int wei[MAX],dep[MAX];
	struct graph
	{
		int next;
		int to;
	}edge[MAX<<1];
	int cnt=1,head[MAX],id[MAX];
	inline void add(int u,int v)
	{ edge[++cnt] = (graph){head[u],v},head[u] = cnt; }
	struct Segment_Tree
	{
		struct TREE
		{
			int val;
			int l,r;
			int lazy;
		}st[MAX<<2];
		inline int ls(int p)
		{ return p<<1; }
		inline int rs(int p)
		{ return p<<1|1; }
		inline void Push_down(int p)
		{
			if(st[p].lazy)
			{
				int opt1 = dep[id[st[ls(p)].l]]&1?1:-1;
				int opt2 = dep[id[st[rs(p)].l]]&1?1:-1;
				st[ls(p)].val += st[p].lazy*opt1;
				st[ls(p)].lazy += st[p].lazy;
				st[rs(p)].val += st[p].lazy*opt2;
				st[rs(p)].lazy += st[p].lazy;
				st[p].lazy = 0;
			}
		}
		inline void build(int p,int l,int r)
		{
			st[p].l = l,st[p].r = r;
			if(l==r)
			{ st[p].val = wei[id[l]]; return ; }
			int mid = (l+r)>>1;
			build(ls(p),l,mid),build(rs(p),mid+1,r);
		}
		inline void update(int p,int l,int r,int val)
		{
			if(l<=st[p].l&&st[p].r<=r)
			{ st[p].val += val*(dep[id[st[p].l]]&1?1:-1),st[p].lazy += val; return ; }
			Push_down(p);
			int mid = (st[p].l+st[p].r)>>1;
			if(l<=mid)
			{ update(ls(p),l,r,val); }
			if(r>mid)
			{ update(rs(p),l,r,val); }
		}
		inline int query(int p,int pos)
		{
			if(st[p].l==st[p].r)
			{ return st[p].val; }
			Push_down(p);
			int ans,mid = (st[p].l+st[p].r)>>1;
			if(pos<=mid)
			{ return query(ls(p),pos); }
			else
			{ return query(rs(p),pos); }
		}
	}Tree;
	int dfn[MAX][2];
	inline void dfs(int u)
	{
		dfn[u][0] = ++cnt;
		dep[u] = dep[fa[u]]+1;
		wei[u] = w[u]-wei[fa[u]];
		id[dfn[u][0]] = u;
		for(re int i=head[u],v; i; i=edge[i].next)
		{ v = edge[i].to; dfs(v); }
		dfn[u][1] = cnt;
	}
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	signed main()
	{
		//freopen("node.in","r",stdin);
		//freopen("my.out","w",stdout);
		cin >> n >> q;
		for(re int i=2; i<=n; i++)
		{ cin >> fa[i] >> w[i]; add(fa[i],i); }
		cnt = 0; dfs(1); Tree.build(1,1,n);
		for(re int i=1,opt; i<=q; i++)
		{
			cin >> opt;
			if(opt==1)
			{
				int u,v,s;
				cin >> u >> v >> s;
				int opt1 = dep[u]&1,opt2 = dep[v]&1;
				int val = Tree.query(1,dfn[u][0])+Tree.query(1,dfn[v][0]);
				//printf("val1=%d val2=%d s=%d\n",val1,val2,s);
				//printf("%d %d\n",dep[u],dep[v]);
				if(opt1==opt2)
				{
					if((s-val)&1)
					{ printf("none\n"); }
					else
					{ printf("%d\n",(opt1?1:-1)*(s-val)/2); }
				}
				else
				{
					if(val==s)
					{ printf("inf\n"); }
					else
					{ printf("none\n"); }
				}
			}
			if(opt==2)
			{
				int u,val;
				cin >> u >> val;
				//printf("%d %d\n",dfn[u][0],dfn[u][1]);
				if(dep[u]&1)
				{ Tree.update(1,dfn[u][0],dfn[u][1],val-w[u]); }
				else
				{ Tree.update(1,dfn[u][0],dfn[u][1],w[u]-val); }
				w[u] = val;
			}
		}
		return 0;
	}
}
signed main()
{ return OMA::main(); }

话说我树状数组写错调了好久,要死

100pts
#include<cctype>
#include<cstdio>
#define MAX 1000010
#define re register
#define int long long
namespace OMA
{
	int n,q,opt[MAX];
	int fa[MAX],w[MAX];
	int wei[MAX],dep[MAX];
	struct graph
	{
		int next;
		int to;
	}edge[MAX];
	int cnt=1,head[MAX],id[MAX];
	inline void add(int u,int v)
	{ edge[++cnt] = (graph){head[u],v},head[u] = cnt; }
	struct BIT
	{
		int tree[MAX];
		inline int lowbit(int x)
		{ return x&-x; }
		inline void update(int x,int y)
		{
			for(re int i=x; i<=n; i+=lowbit(i))
			{ tree[i] += y; }
		}
		inline void build()
		{
			for(re int i=1; i<=n; i++)
			{ update(i,wei[id[i]]*opt[id[i]]-wei[id[i-1]]*opt[id[i-1]]); }
		}
		inline int query(int x)
		{
			int res = 0;
			for(re int i=x; i; i-=lowbit(i))
			{ res += tree[i]; }
			return res*opt[id[x]];
		}
	}BIT;
	int dfn[MAX][2];
	inline void dfs(int u)
	{
		dfn[u][0] = ++cnt;
		id[dfn[u][0]] = u;
		dep[u] = dep[fa[u]]+1;
		wei[u] = w[u]-wei[fa[u]];
		for(re int i=head[u],v; i; i=edge[i].next)
		{ v = edge[i].to; dfs(v); }
		dfn[u][1] = cnt;
	}
	struct stream
	{
		char buf[1<<21],*p1=buf,*p2=buf;
		#define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=0; s=0; char ch=gc();
			while(!isdigit(ch)){ w |= ch=='-'; ch=gc(); }
			while(isdigit(ch)){ s = (s<<1)+(s<<3)+(ch^48); ch=gc(); }
			return s = w?-s:s,*this;
		}
	}cin;
	signed main()
	{
		cin >> n >> q;
		for(re int i=2; i<=n; i++)
		{ cin >> fa[i] >> w[i]; add(fa[i],i); }
		cnt = 0; dfs(1); 
		for(re int i=1; i<=n; i++)
		{ opt[i] = dep[i]&1?1:-1; }
		BIT.build();
		for(re int i=1,opt1; i<=q; i++)
		{
			cin >> opt1;
			if(opt1==1)
			{
				int u,v,s;
				cin >> u >> v >> s;
				int val = BIT.query(dfn[u][0])+BIT.query(dfn[v][0]);
				if(opt[u]==opt[v])
				{
					if((s-val)&1)
					{ printf("none\n"); }
					else
					{ printf("%lld\n",opt[u]*(s-val)/2); }
				}
				else
				{
					if(val==s)
					{ printf("inf\n"); }
					else
					{ printf("none\n"); }
				}
			}
			if(opt1==2)
			{
				int u,val;
				cin >> u >> val;
				BIT.update(dfn[u][0],opt[u]*(val-w[u]));
				BIT.update(dfn[u][1]+1,-opt[u]*(val-w[u]));
				w[u] = val;
			}
		}
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T3

考场硬刚,啥也没写出来,暴力也写假,爬了爬了。

正解:

树状数组+扫描线?

不会,咕了

反思总结:

  1. 睡好觉....

  2. 注意开题顺序,题面读全,不要忽略数据范围。

  3. 不要硬刚一道题,时间分配要合理。

posted @ 2021-08-09 20:30  -OMA-  阅读(70)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end