LG-P1250 种树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xu0_zy/article/details/83660843

题目链接

这题主要有贪心和差分两种解法。

①贪心
我们想当然的要进行排序,具体按照左边界还是右边界自己定。作者是按照右边界从大到小排序的。

我们当然希望一棵树能同时处于多个区间,这样就可以少种树。所以每个区间,我们都从它的最右边开始种树。

第一个问题,我们怎么知道这个区间里需要种几棵树?因为上一个区间里的部分树可能已经 “溢出” 到当前区间。
作者的解决法案是把利用树状数组来统计。

第二个问题,树具体种在哪里?当前的区间可能出现如下情况(#表示没有树,@表示树)
####@@@@######@@@@@#####@@@@###
我们发现并不是按照顺序,一顿地插树苗就可以解决战斗,因为可以种树的区间不连续。

由于每次种 1 棵,作者利用并查集来合并有树的区间。这样就能快速找到下一个能种树的位置。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int rad()
{
	int ret=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
const int maxn=30005,maxm=5005;
int fa[maxn],n,m,ans,c[maxn];
struct js{
	int L,R,s;
	bool operator <(const js&b)const{return L>b.L;}
}a[maxm];
void add(int x){for(int i=x;i<=n;i+=i&-i)++c[i];}
int get(int x){int s=0;while(x)s+=c[x],x-=x&-x;return s;}
int FA(int x){return x==fa[x]?x:fa[x]=FA(fa[x]);}
int main()
{
	n=rad();m=rad();ans=0;
	for (int i=1;i<=n+1;++i) fa[i]=i;
	for (int i=1;i<=m;++i) a[i]=(js){rad(),rad(),rad()};
	sort(a+1,a+m+1);
	for (int i=1;i<=m;++i)
	{
		for (int j=get(a[i].R)-get(a[i].L-1);j<a[i].s;++j)
		{
			int nxt=FA(a[i].L);
			if (nxt>a[i].R) continue;
			add(nxt);
			fa[nxt]=FA(nxt+1);
			++ans;
		}
	}
	printf("%d\n",ans);
	return 0;
}

②差分
我们假设树已经种好了,然后统计一趟前缀和,若存在要求 L L R R 区间必须又 T T 棵树,那么
s u m [ R ] s u m [ L 1 ] &gt; = T sum[R]-sum[L-1]&gt;=T
还有就是 1 &gt; = s u m [ i ] s u m [ i 1 ] &gt; = 0 1 &gt;= sum[i]-sum[i-1] &gt;=0
我们这样可以建图:
s u m sum 转化为 d i s dis d i s dis 表示最长路。
对于每组 L , R T L , R,T ,建 L 1   = &gt; R L-1 \ =&gt; R 长度为 T T 的边。
对于 i [ 0 , n ] i\in[0,n] i = &gt; i 1 i =&gt; i-1 长度为 0 0 i 1   = &gt; i i-1\ =&gt; i 长度为 1 -1 的边。
然后刷最长路就好了。最后的答案就是 0 0 n n 的最长路。

//这次的spfa写丑了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int rad()
{
	int ret=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
const int maxn=30005,maxm=5005,maxe=(maxn<<1)+maxm;
int n,m,lnk[maxn],nxt[maxe],son[maxe],w[maxe],tot,dis[maxn],q[maxn],til,hea,vis[maxn];
void spfa()
{
	memset(dis,192,sizeof dis);
	*dis=q[til=1]=hea=0;
	while (hea!=til)
	{
		if (++hea==maxn) hea=0;
		int x=q[hea];vis[x]=0;
		for (int i=lnk[x];i;i=nxt[i])
		{
			int y=son[i];
			if (dis[x]+w[i]>dis[y])
			{
				dis[y]=dis[x]+w[i];
				if (!vis[y])
				{
					vis[y]=1;
					if (++til==maxn) til=0;
					q[til]=y;
				}
			}
		}
	}
}
void add(int x,int y,int z){son[++tot]=y;nxt[tot]=lnk[x];w[lnk[x]=tot]=z;}
int main()
{
	n=rad();m=rad();
	for (int i=1,x,y,z;i<=m;++i)
	{
		x=rad();y=rad();z=rad();
		add(x-1,y,z);
	}
	for (int i=1;i<=n;++i) add(i-1,i,0),add(i,i-1,-1);
	spfa();
	printf("%d\n",dis[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/83660843
今日推荐