2024/8/16

P1533 可怜的狗狗

裸的主席树,但是我想到一种其它的做法。

用莫队加上平衡树,原因为题目保证 \(a_i\) 互不相同,算了一下复杂度勉强能过。

平衡树的话可以使用 pbds 内置的那颗。

跑得飞快,碾压主席树。

点击查看代码
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
using namespace  __gnu_pbds;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,m;
int a[maxn];
int id[maxn],len;
struct no
{
	int l,r,k,pos;
	inline friend bool operator < (no q,no w) 
	{
		if(id[q.l]==id[w.l])
		{
			if(id[q.l]&1) return q.r<w.r;
			else return q.r>w.r;
		}
		else
		{
			return q.l<w.l;
		}
	}
}q[maxn];
int ans[maxn];
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
	}
	for(int i=1;i<=m;i++)
	{
		q[i]={read(),read(),read(),i};
	}
	len=sqrt(n*1.0);
	for(int i=1;i<=n;i++)id[i]=(i-1)/len+1;
	sort(q+1,q+m+1);
	int l=0,r=0;
	for(int i=1;i<=m;i++)
	{
		while(r<q[i].r)
		{
			r++;
			tr.insert(a[r]);
		}
		while(r>q[i].r)
		{
			tr.erase(a[r]);
			r--;
		}
		while(l<q[i].l)
		{
			tr.erase(a[l]);
			l++;
		}
		while(l>q[i].l)
		{
			l--;
            tr.insert(a[l]);
		}
		int res=findnum(q[i].k);
		ans[q[i].pos]=res;
	}
	for(int i=1;i<=m;i++)
	printf("%lld\n",ans[i]);
	return 0;
}

P1668 [USACO04DEC] Cleaning Shifts S

典型线段树优化DP,设 \(dp_i\) 表示区间 \([1,i]\) 所需最小线段数量。初始化所有 \(l=1\) 的线段都有 \(dp_r=1\)

然后按照 \(r\) 排序,对于当前的 \(r\),转移的时候显然 \(dp_r=dp_j+1~~ (l-1\le j \le r)\)

然后一个线段树搞一下就结束了。

点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace  __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,T;
struct no
{
	int l,r;
	inline friend bool operator < (no x,no y)
	{
		return x.r<y.r||x.r==y.r&&x.l<y.l;
	}
}a[maxn];
struct Seg
{
	int l,r,d;
}t[maxn<<2];
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		t[p].d=1e9+7;
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
	t[p].d=min(t[p*2].d,t[p*2+1].d);
}
void upd(int p)
{
	t[p].d=min(t[p*2].d,t[p*2+1].d);
}
void change(int p,int x,int k)
{
	if(t[p].l==t[p].r)
	{
		t[p].d=min(t[p].d,k);
		return ;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(x<=mid)change(p<<1,x,k);
    else change(p<<1|1,x,k);
    upd(p);
}
int ask(int p,int l,int r)
{
	if(t[p].l>=l&&t[p].r<=r)
	{
		return t[p].d;
	}
	int mid=(t[p].l+t[p].r)/2,re=1e9+7;
	if(mid>=l)re=min(re,ask(p*2,l,r));
	if(mid<r)re=min(re,ask(p*2+1,l,r));
    return re; 
}
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>n>>T;
	for(int i=1;i<=n;i++)
	{
		a[i].l=read(),a[i].r=read();
	}
	build(1,1,T);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)if(a[i].l==1)change(1,a[i].r,1);
	for(int i=1;i<=n;i++)
	{
		int mii=ask(1,a[i].r,a[i].r);
		mii=min(mii,ask(1,a[i].l-1,a[i].r-1)+1);
		change(1,a[i].r,mii);
	}
	int ans=ask(1,T,T);
	cout<<(ans>1e9?-1:ans);
	return 0;
}

P6348 [PA2011] Journeys

线段树优化建图板子。

需要注意的是,一不小心就会RE,所以稍微改一下建图方式每次开一个虚拟点进行连边即可。

空间快爆掉。

点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace  __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,m,s,k;
struct Seg
{
	int l,r;
}t[5000100];
struct no
{
	int y,v;
};
vector<no> G[maxn];
void add(int x,int y,int v)
{
	G[x].push_back({y,v});
}
int id[maxn];
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		id[l]=p;
		return ;
	}
	int mid=(l+r)>>1;
	add(p,p*2,0);add(p,p*2+1,0);
	add(p*2+k,p+k,0);add(p*2+1+k,p+k,0);
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
vector<int> vv;
void change(int p,int l1,int r1)
{
	if(t[p].l>=l1&&t[p].r<=r1)
	{
		vv.push_back(p);
		return ;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(l1<=mid)change(p*2,l1,r1);
	if(mid<r1)change(p*2+1,l1,r1);
}
void change2(int p,int l1,int r1)
{
	if(t[p].l>=l1&&t[p].r<=r1)
	{
		for(auto i : vv)
		{
			add(i+k,p,1);
			add(p+k,i,1);
		}
		return ;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(l1<=mid)change2(p*2,l1,r1);
	if(mid<r1)change2(p*2+1,l1,r1);
}
struct dii
{
	int y,id;
	inline friend bool operator < (dii x,dii y)
	{
		return x.y>y.y;
	}
};
int dis[maxn];
bool vis[maxn];
void distla(int s)
{
	memset(dis,0x3f,sizeof dis);
	priority_queue<dii> q;
	dis[s]=0;
	q.push({0,s});
	while(!q.empty())
	{
		int u=q.top().id;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto i : G[u])
		{
			int y=i.y,v=i.v;
			if(dis[u]+v<dis[y])
			{
				dis[y]=dis[u]+v;
				if(!vis[y])
				q.push({dis[y],y});
			}
		}
	}
}
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>n>>m>>s;
	k=5e5+1;
	build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		add(id[i],id[i]+k,0);
		add(id[i]+k,id[i],0);
	}
	for(int i=1;i<=m;i++)
	{
		int l1=read(),r1=read(),l2=read(),r2=read();
		vv.clear();
		change(1,l1,r1);
		change2(1,l2,r2);
	}
	distla(id[s]+k);
	for(int i=1;i<=n;i++)
	cout<<(dis[id[i]]==0x3f3f3f3f3f3f3f3fll?-1:dis[id[i]])<<endl;
	return 0;
}

P2197 【模板】Nim 游戏

刚刚邱爹来讲课了,所以找了这道题巩固一下。

其实很简单,但是很神奇。

因为取最大的话最高位一定是 \(1\),并且一定有一个办法使它改变以后总异或和为 \(0\),且异或之后最高位一定变成 \(0\),所以满足题目条件。

代码很短:

点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace  __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const double eps=1e-10;
int T;
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>T;
	while(T--)
	{
		int n=read();
		int x=read();
		for(int i=2;i<=n;i++)x^=read();
		if(!x)puts("No");
		else puts("Yes");
	}
	return 0;
}

[ABC238E] Range Sums

根据前缀和公式 \(sum_r-sum_{l-1}=sum\) 可知,这三个变量知二求三。

所以每次我们让 \(l-1\)\(r\) 联通,看看最后 \(0\)\(n\) 能否联通,并查集维护即可。

点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace  __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const double eps=1e-10;
int n,q;
struct no
{
	int l,r;
}a[maxn];
int fa[maxn];
int gf(int x){return fa[x]==x?x:fa[x]=gf(fa[x]);}
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>n>>q;
	for(int i=0;i<=n;i++)fa[i]=i;
	for(int i=1;i<=q;i++)a[i]={read(),read()};
	for(int i=1;i<=q;i++)
	{
		int x=gf(a[i].l-1),y=gf(a[i].r);
		fa[x]=y;
	}
	cout<<(gf(0)==gf(n)?"Yes":"No");
	return 0;
}

P8779 [蓝桥杯 2022 省 A] 推导部分和

类似上一道题,但是需要带权并查集,需要维护区间和,合并式子稍微一推就出来了。

每次询问直接输出两个数组值的差即可。

点击查看代码
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace  __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//从小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const double eps=1e-10;
int fa[maxn],v[maxn];
int n,m,q;
int gf(int x)
{
	if(fa[x]==x)return x;
	int f=gf(fa[x]);
	v[x]+=v[fa[x]];
	return fa[x]=f;
}
signed main()
{
#ifdef Lydic
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
	cin>>n>>m>>q;
	for(int i=0;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int l=read()-1,r=read(),sum=read();
		int fl=gf(l),fr=gf(r);
		if(fl!=fr)
		{
			fa[fr]=fl;
			v[fr]=v[l]-v[r]+sum;
		}
	}
	while(q--)
	{
		int l=read()-1,r=read();
		int fl=gf(l),fr=gf(r);
		if(fl!=fr)puts("UNKNOWN");
		else cout<<v[r]-v[l]<<'\n';
	}
	return 0;
}
posted @ 2024-08-16 16:09  Redamancy_Lydic  阅读(8)  评论(0编辑  收藏  举报