Problem: Intervals
Description: 给你N个区间,每个区间都有一个C,C表示区间中至少要有C个数字,现在问你至少要多少个数字才能满足所有的区间条件。
Solution_1: 差分约束系统。先看这个问题,如果这些区间都不重叠的话,那么这个问题就很简单。但是并不是这样的,对于区间和问题我们总喜欢表示成这样的形式 T[b]−T[a−1]>=C 。题中有很多这样的条件,那么是不是很像差分约束系统,这样我们就转化成求0到区间端点的最长路。这样的最长路就是题目中的所求了。但是要注意的是,这里是求最长路,与求最短路不一样,还有当有这些条件是不行的,因为这样无法保证这个图是连通的。我们得从题目中提取些不等式出来,对了就是 T[x]−T[x−1]>=0,T[x−1]−T[x]>=−1 。有了这些条件后,就是简单的差分约束求最长路了, spfa 就好。
Solution_2: 贪心+树状数组,或者再优化些加上并查集。我们知道,对于区间排好序后,我们一个个区间遍历,数字越放到区间右端点的方向越容易被下一个区间覆盖,这样就可以减少数字的数量了。这里用到树状数组是因为要对 [1,X] 这段区间进行求和。众所周知树状数组是基于二分的,所以速度很快。那么并查集又是怎么回事呢?这也是我看到Discuss中的一个大神用的优化,真的是开眼了,学到了并查集的新用法。这里用并查集是来解决判重问题的,大家注意,如果不用并查集,那么就要用一个 used 数组来标识这个点是不是有数字了,但是如果用并查集的话我们每次 search 后把它挂到它前一个点上,那么下次 search 的时候直接就找到了没有数字并且最后的一个点。这样完美的解决了用 used 数组要从后先前遍历的问题。
这里有一点要注意,就是区间的排序,之前我一直都是按左端点作为首关键字排序的,所以一直WA。后来在洗澡的时候突然想到了按左端点排序有可能出现反例。看这样的一组数据:
我们按左端点排序得到 [1,100],[4,8] 。由上面的解法,我们会在100这个点填上数字,然后在8这个点填上数字。这样明显不是最优的。那我们按右端点排序得到 [4,8],[1,100] 。我们在8这个点填上数字,然后查询下 [1,100] 有1个数字了,因此不用填了,因此最优答案是1。
Code(差分约束):
#include
#include
#include
#include
#include
#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))
using namespace std;
const int M=4*50000+5;
const int INF=0x3f3f3f3f;
typedef struct tagNode{
int to,c;
int next;
}Node;
Node map[M];
int head[M];
int top,but,m;
int I;
int dis[M];
int de[M];
bool used[M];
void add_edge(int from,int to,int c)
{
map[I].to=to;
map[I].c=c;
map[I].next=head[from];
head[from]=I++;
}
bool spfa(int src)
{
for(int i=0;i0,used[i]=false;
queue<int> que;
que.push(src);
de[src]=1;
used[src]=true;
dis[src]=0;
while(!que.empty()){
int pre=que.front();
que.pop();
used[pre]=false;
for(int i=head[pre];i+1;i=map[i].next){
int tmp=map[i].to;
if(dis[tmp]map[i].c){
dis[tmp]=dis[pre]+map[i].c;
if(!used[tmp]){
used[tmp]=true;
que.push(tmp);
++de[tmp];
if(de[tmp]>top)
return false;
}
}
}
}
return true;
}
int main()
{
while(cin>>m){
int a,b,c;
top=-INF;
but=INF;
I=0;
for(int i=0;i1;
while(m--){
scanf("%d%d%d",&a,&b,&c);
add_edge(a-1,b,c);
top=MAX(b,top);
but=MIN(a-1,but);
}
for(int i=but+1;i<=top;i++)
add_edge(i-1,i,0),
add_edge(i,i-1,-1);
spfa(but);
cout<return 0;
}
Code(贪心+树状数组+ used 数组):
#include
#include
#include
#include
#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))
using namespace std;
const int M=50000+50;
typedef struct tagNode{
int a,b;
int c;
}Node;
int m;
int a[M];
bool used[M];
Node qu[M];
int top;
bool cmp(Node a,Node b)
{
if(a.b!=b.b)
return a.breturn a.aint lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
for(int i=x;i<=top;i+=lowbit(i))
++a[i];
}
int find(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=a[i];
return sum;
}
int work()
{
memset(used,false,sizeof(used));
int ans=0;
for(int i=1;i<=m;i++){
int sum=find(++qu[i].b)-find(++qu[i].a-1);
if(sumint tmp=qu[i].c-sum;
ans+=tmp;
for(int j=qu[i].b;j>=qu[i].a&&tmp;j--)
if(!used[j])
update(j),used[j]=true,--tmp;
}
}
return ans;
}
int main()
{
while(~scanf("%d",&m)){
top=-1;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
top=MAX(qu[i].b+1,top);
memset(a,0,sizeof(a));
sort(qu+1,qu+m+1,cmp);
int ans=work();
printf("%d\n",ans);
}
return 0;
}
Code(贪心+树状数组+并查集):
#include
#include
#include
#include
#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))
using namespace std;
const int M=50000+50;
typedef struct tagNode{
int a,b;
int c;
}Node;
int m;
int a[M];
int p[M];
Node qu[M];
int top;
bool cmp(Node a,Node b)
{
if(a.b!=b.b)
return a.breturn a.aint lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
for(int i=x;i<=top;i+=lowbit(i))
++a[i];
}
int find(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=a[i];
return sum;
}
int search(int x)
{
return x==p[x]? x:p[x]=search(p[x]);
}
int work()
{
for(int i=0;iint ans=0;
for(int i=1;i<=m;i++){
int sum=find(++qu[i].b)-find(++qu[i].a-1);
if(sumint tmp=qu[i].c-sum;
ans+=tmp;
for(int now=qu[i].b;tmp;--tmp){
now=search(now);
update(now);
p[now]=now-1;
--now;
}
}
}
return ans;
}
int main()
{
while(~scanf("%d",&m)){
top=-1;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
top=MAX(qu[i].b+1,top);
memset(a,0,sizeof(a));
sort(qu+1,qu+m+1,cmp);
int ans=work();
printf("%d\n",ans);
}
return 0;
}