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;
}



目录
相关文章
|
7月前
|
开发框架 .NET
poj 3468 A Simple Problem with Integers线段树区间修改
题目意思很简单,有N个数,Q个操作, Q l r 表示查询从l到r 的和,C l r v 表示将从l到r 的值加上v,明显的线段树,不知道线段树的人肯定暴力,肯定超时,哈哈!!
19 0
|
机器学习/深度学习 Windows
The 2022 ICPC Asia Regionals Online Contest (I)-D题题解(DFS暴搜+剪枝+打表去重+二分)
时间复杂度:O(227 + nlog(n) + T * log(n)),227是DFS打表的时间,nlog(n)是vertor排序的时间,T*log(n)是询问次数和二分搜答案的时间。(如果算错了,评论或者私信指出谢谢)
124 0
The 2022 ICPC Asia Regionals Online Contest (I)-D题题解(DFS暴搜+剪枝+打表去重+二分)
AtCoder Beginner Contest 221 E - LEQ(组合数学 树状数组)
AtCoder Beginner Contest 221 E - LEQ(组合数学 树状数组)
131 0
AtCoder Beginner Contest 203(Sponsored by Panasonic) D.Pond(二分+二维前缀和)
AtCoder Beginner Contest 203(Sponsored by Panasonic) D.Pond(二分+二维前缀和)
65 0
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
88 0
|
机器学习/深度学习
AtCoder Beginner Contest 215 F - Dist Max 2 (二分 单调队列)
AtCoder Beginner Contest 215 F - Dist Max 2 (二分 单调队列)
106 0
|
Windows
German Collegiate Programming Contest 2019 H . Historical Maths (二分 大数)
German Collegiate Programming Contest 2019 H . Historical Maths (二分 大数)
63 0
German Collegiate Programming Contest 2019 H . Historical Maths (二分 大数)
AtCoder Beginner Contest 226 E - Just one(dfs求连通块 组合数学)
AtCoder Beginner Contest 226 E - Just one(dfs求连通块 组合数学)
82 0
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
92 0
CodeForces 1195C Basketball Exercise (线性DP)
CodeForces 1195C Basketball Exercise (线性DP)
84 0