NOIP day -2 笔记

马上NOIP了,写点笔记攒一下rp

P2824[排序]

十分巧妙的数据结构题,关键点在于如何正确的处理排序的结果。
直接暴力做显然会被T飞,由此我们需要考虑用一种复杂度更低的方法去标记排序。
对于一个点 \(x\) 做包含 \(x\) 的序列的排序,标记 \(\leq val_x\)的点为 \(0\), \(>x\) 的点为 \(1\) ,这样对于查询点 \(p\),我们只需要对其进行二分,找到符合条件的最大值即可。
序列问题上,我们使用线段树进行维护,由于每次二分都要重新建一次树,所以总时间复杂度为 \(O(m\log^2n)\)

AC Code
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define endll " "
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define lowbit(x) x&-x
#ifndef ONLINE_JUDGE
#pragma GCC optimize(0)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#endif
using namespace std;
const int MAXN=500050;
const int INF=0x3f3f3f3f;
const int MOD=998244353;
int n,tot,a[MAXN],b[MAXN],ed[MAXN],cnt,u,v,w,l,r,pos,ans,m;
struct lane
{
	int opt,l,r;
}q[MAXN];
struct tree
{
	int tag,val;
}t[MAXN*4];
void pushup(int i)
{
	t[i].val=(t[i*2].val+t[i*2+1].val);
}
void pushdown(int i,int l,int r)
{
	if(t[i].tag!=-1)
	{
		int mid=(l+r) >> 1;
		t[i*2].val=(mid-l+1)*t[i].tag;
		t[i*2+1].val=(r-mid)*t[i].tag;
		t[i*2].tag=t[i].tag;
		t[i*2+1].tag=t[i].tag;
		t[i].tag=-1;
	}
}
void build(int i,int l,int r)
{
	t[i].tag=-1;
	if(l==r)
	{
		t[i].val=b[l];
		return;
	}
	int mid=(l+r) >> 1;
	build(i*2,l,mid);
	build(i*2+1,mid+1,r);
	pushup(i);
}
void modify(int i,int l,int r,int ql,int qr,int val)
{
	if(l>qr || r<ql)
		return;
	if(l>=ql && r<=qr)
	{
		t[i].val=val*(r-l+1);
		t[i].tag=val;
		return;
	}
	pushdown(i,l,r);
	int mid=(l+r) >> 1;
	if(ql<=mid)
		modify(i*2,l,mid,ql,qr,val);
	if(qr>mid)
		modify(i*2+1,mid+1,r,ql,qr,val);
	pushup(i);
}
int query(int i,int l,int r,int ql,int qr)
{
	if(l>qr ||r<ql)
		return 0;
	if(l>=ql && r<=qr)
		return t[i].val;
	pushdown(i,l,r);
	int mid=(l+r) >> 1;
	int res=0;
	if(ql<=mid)
		res+=query(i*2,l,mid,ql,qr);
	if(qr>mid)
		res+=query(i*2+1,mid+1,r,ql,qr);
	return res;
}
bool check(int mid,int pos)
{
	for(int i=1;i<=n;i++)
	{
		if(mid>a[i])
			b[i]=0;
		else
			b[i]=1;
	}
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int opt=q[i].opt,l=q[i].l,r=q[i].r;
		if(!opt)
		{
			int res=query(1,1,n,l,r);
			modify(1,1,n,l,r-res,0);
			modify(1,1,n,r-res+1,r,1);
		}
		else
		{
			int res=query(1,1,n,l,r);
			modify(1,1,n,l+res,r,0);
			modify(1,1,n,l,l+res-1,1);
		}
	}
	if(query(1,1,n,pos,pos))
		return 1;
	return 0;
}
signed main()
{
#ifndef ONLINE_JUDGE
	fre("sort");
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for(int i=1;i<=n;i++)
		cin >> a[i];
	for(int i=1;i<=m;i++)
		cin >> q[i].opt >> q[i].l >> q[i].r;
	cin >> pos;
	l=1,r=n;
	while(l<=r)
	{
		int mid=(l+r) >> 1;
		if(check(mid,pos))
		{
			ans=mid;
			l=mid+1;
		}
		else
			r=mid-1;
	}
	cout<<ans;
	return 0;
}

P3128 [USACO15DEC] Max Flow P

树上差分+树链剖分,其实没啥可说的,挺板的。。。

AC Code
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define endll " "
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define lowbit(x) x&-x
#ifndef ONLINE_JUDGE
#pragma GCC optimize(0)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#endif
using namespace std;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int lcm(int x,int y){return x/gcd(x,y)*y;}
int ksm(int x,int m,int mod)
{
	int res=1,bas=x%mod;
	while(m)
	{
		if(m&1)
			res=(res*bas)%mod;
		bas=(bas*bas)%mod;
		m >>= 1;
	}
	return res;
}
const int MAXN=500050;
const int INF=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
int n,m,k,T,l,r,u,v,w,x,y,z,cnt,tot,ans,head[MAXN],a[MAXN],b[MAXN],fa[MAXN],dfn[MAXN],siz[MAXN],son[MAXN];
int dep[MAXN],ms,top[MAXN],tim,t[MAXN*2];
struct edge
{
	int to,nxt;
}e[MAXN];
void add_edge(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}
void update(int x,int val)
{
	for(int i=x;i<=n;i+=lowbit(i))
		t[i]+=val;
}
int query(int x)
{
	int res=0;
	for(int i=x;i;i-=lowbit(i))
		res+=t[i];
	return res;
}
void modify(int l,int r)
{
	update(l,1);
	update(r+1,-1);
}
void dfs1(int u,int f)
{
	dep[u]=dep[f]+1;
	siz[u]=1;
	fa[u]=f;
	int ms=-1;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f)
			continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(ms<siz[v])
		{
			ms=siz[v];
			son[u]=v;
		}
	}
}
void dfs2(int u,int f)
{
	dfn[u]=++tim;
	top[u]=f;
	if(!son[u])
		return;
	dfs2(son[u],f);
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa[u] || v==son[u])
			continue;
		dfs2(v,v);
	}
}
void lca(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])
			swap(u,v);
		modify(dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])
		swap(u,v);
	modify(dfn[u],dfn[v]);
}
signed main()
{
#ifndef ONLINE_JUDGE
	fre("max");
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> k;
	for(int i=1;i<n;i++)
	{
		cin >> u >> v;
		add_edge(u,v);
		add_edge(v,u);
	}
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=k;i++)
	{
		cin >> u >> v;
		lca(u,v);
	}
	for(int i=1;i<=n;i++)
		ans=max(ans,query(i));
	cout<<ans;
	return 0;
}

P5597 [XR-4]复读

对于任意一个节点\(u\),总有一个后继节点\(v\)与根节点相对称(因为复制操作就等于递归操作)。
由此,我们考虑直接枚举所有点\(u\),然后根据上述所说性质找到对应的点\(v\),每一次枚举都需要建一次新树,统计\(ans\),也就是子树的大小,最后找到最大值。(其实感觉还挺暴力的)

AC Code
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define endll " "
#define fre(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define lowbit(x) x&-x
#ifndef ONLINE_JUDGE
#pragma GCC optimize(0)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#endif
using namespace std;
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int lcm(int x,int y){return x/gcd(x,y)*y;}
int ksm(int x,int m,int mod)
{
	int res=1,bas=x%mod;
	while(m)
	{
		if(m&1)
			res=(res*bas)%mod;
		bas=(bas*bas)%mod;
		m >>= 1;
	}
	return res;
}
const int MAXN=500050;
const int INF=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
int n,m,l,r,u,v,w,x,y,z,cnt1,cnt2,tot,ans=INF,head[MAXN],a[MAXN],b[MAXN],pos1,pos2;
struct lane
{
	int l,r;
}t1[MAXN],t2[MAXN];
int readin()
{
	int val=getchar()-'0';
	int u=++cnt1;
	if(val&1)
		t1[u].l=readin();
	if(val&2)
		t1[u].r=readin();
	return u;
}
void dfs(int u,int v)
{
	if(u==pos1 || v==pos2)
	{
		pos2=v;
		v=1;
	}
	if(t1[u].l)
	{
		if(!t2[v].l)
			t2[v].l=++cnt2;
		dfs(t1[u].l,t2[v].l);
	}
	if(t1[u].r)
	{
		if(!t2[v].r)
			t2[v].r=++cnt2;
		dfs(t1[u].r,t2[v].r);
	}
}
void solve(int u,int d)
{
	pos1=u;
	pos2=0;
	cnt2=1;
	memset(t2,0,sizeof(t2));
	dfs(1,1);
	ans=min(ans,cnt2*2-2-d);
	if(t1[u].l)
		solve(t1[u].l,d+1);
	if(t1[u].r)
		solve(t1[u].r,d+1);
}
signed main()
{
#ifndef ONLINE_JUDGE
	fre("1126");
#endif
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	readin();
	solve(1,0);
	cout<<ans;
	return 0;
}

一些碎碎念

作为一个弱省OIer,可能NOIP就是我的最后一场比赛了,希望后天能有个好成绩吧,,,,

posted @ 2025-11-27 20:45  KLaneX  阅读(22)  评论(0)    收藏  举报