版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}
②差分
我们假设树已经种好了,然后统计一趟前缀和,若存在要求
到
区间必须又
棵树,那么
还有就是
我们这样可以建图:
把
转化为
,
表示最长路。
对于每组
,建
长度为
的边。
对于
建
长度为
和
长度为
的边。
然后刷最长路就好了。最后的答案就是
到
的最长路。
//这次的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;
}