AtCoder Beginner Contest 216 G - 01Sequence (并查集 贪心 树状数组 差分约束)

简介: AtCoder Beginner Contest 216 G - 01Sequence (并查集 贪心 树状数组 差分约束)

题意

对于每个要求x[ l , r ],x都满足[ l , r ]中1的个数> = x

构造出这个序列满足上述要求,并且1的个数最小。

思路1:

先按照右端点排序,贪心的考虑,从右端点开始填1,并且用并查集找下一个可以填1的位置。

每次询问[ l , r ]的区间和,如果已经> = x的话就不用再考虑这个区间了。

单点修改区间求和可以用树状数组,时间复杂度O ( n l o g n )

代码1:

const int maxn=2e5+100;
int n,m,tr[maxn],root[maxn],ans[maxn];
struct node{
  int l,r,num;
}q[maxn];
bool cmp(node a,node b){
  return a.r<b.r;
}
int Find(int x){
  if(x!=root[x]) root[x]=Find(root[x]);
  return root[x];
}
int lowbit(int x){return x&-x;}
void update(int pos){
  while(pos<=n) tr[pos]++,pos+=lowbit(pos);
}
int query(int pos){
  int res=0;
  while(pos) res+=tr[pos],pos-=lowbit(pos);
  return res;
}
int main() {
  n=read,m=read;
  rep(i,1,m){
    q[i].l=read,q[i].r=read,q[i].num=read;
  }
  sort(q+1,q+1+m,cmp);
  rep(i,1,n) root[i]=i;
  rep(i,1,m){
    int now=query(q[i].r)-query(q[i].l-1);
    if(now>=q[i].num) continue;
    q[i].num-=now;
    for(int j=Find(q[i].r);j>=q[i].l&&q[i].num;j=Find(j)){
      update(j);root[j]=Find(j-1);q[i].num--;ans[j]=1;
    }
  }
  for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
  return 0;
}

思路2

设x i表示序列中[ 1 , i ]的1的个数,给出的条件就可以转化成x r − x l − 1 > = x,这样就变成经典的差分约束问题了,由于求的是x n的最小值,从l − 1 − > r连一条权值为x的边,跑最长路。由于边权为正,所以不能用d i j k s t r a又会被卡。

所以就转化成0的个数后跑最短路,用d i j k s t r a,注意要从0开始。

代码2

int n,m,dis[maxn];
vector<PII>g[maxn];
bool st[maxn];
void dij(){
    memset(dis,0x3f,sizeof dis);
    dis[0]=0;
    ///建立一个维护最小值的优先队列
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    heap.push({0,0});///起始点放入队列
    while(heap.size()){
        PII t=heap.top();///最小值
        heap.pop();
        int ver=t.second,d=t.first;
        if(st[ver]) continue;///该点更新
        st[ver]=true;
        for(int i=0;i<g[ver].size();i++){
            int j=g[ver][i].first,w=g[ver][i].second;
            if(dis[j]>d+w){
                dis[j]=d+w;
                heap.push({dis[j],j});
            }
        }
    }
}
int main(){
  n=read,m=read;
  rep(i,1,m){
    int l=read,r=read,x=read;
    x=r-l+1-x;
    g[l-1].push_back({r,x});
  }
  rep(i,0,n-1){
    g[i].push_back({i+1,1});
    g[i+1].push_back({i,0}); 
  }
  dij();
  rep(i,1,n) printf("%d ", (dis[i]-dis[i-1])^1);
    return 0;
}



目录
相关文章
|
算法
The kth great number(小根堆思想,模板题)
The kth great number(小根堆思想,模板题)
53 0
|
开发框架 .NET
poj 3468 A Simple Problem with Integers线段树区间修改
题目意思很简单,有N个数,Q个操作, Q l r 表示查询从l到r 的和,C l r v 表示将从l到r 的值加上v,明显的线段树,不知道线段树的人肯定暴力,肯定超时,哈哈!!
34 0
AtCoder Beginner Contest 221 E - LEQ(组合数学 树状数组)
AtCoder Beginner Contest 221 E - LEQ(组合数学 树状数组)
158 0
AtCoder Beginner Contest 203(Sponsored by Panasonic) D.Pond(二分+二维前缀和)
AtCoder Beginner Contest 203(Sponsored by Panasonic) D.Pond(二分+二维前缀和)
93 0
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
134 0
|
机器学习/深度学习
AtCoder Beginner Contest 215 F - Dist Max 2 (二分 单调队列)
AtCoder Beginner Contest 215 F - Dist Max 2 (二分 单调队列)
147 0
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
127 0
AtCoder Beginner Contest 214 D.Sum of Maximum Weights (思维 并查集)
AtCoder Beginner Contest 214 D.Sum of Maximum Weights (思维 并查集)
121 0
AtCoder Beginner Contest 203 Pond(二分+二维前缀和)
大体思路: 二分,将原矩阵根据二分的值变成01矩阵,如果元素值> val 就变为1,否则0 对于k * k 的矩阵,统计区域内元素之和,如果 sum < ⌊k2 / 2⌋ + 1,意味着当前k * k矩阵的中位数小于x,而x是我们的答案(最小中位数), ①sum < ⌊k2 / 2⌋ + 1 情况下x取得太大,r = mid ②反之,x还可能取更小的,l = mid 但是需要注意下l的初始值,当取0 or 1的时候是会wa掉的:
253 0
AtCoder Beginner Contest 203 Pond(二分+二维前缀和)

热门文章

最新文章