hdu3275线段树

#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 100010
char ch[maxn];
struct Tree
{
    int l,r,store,len;
    bool lson,rson;
    bool flag;
}tree[maxn*3];
void build(int l,int r,int pos)
{
    tree[pos].l=l;
    tree[pos].r=r;
    tree[pos].len=r-l+1;
    tree[pos].flag=false;
    if(tree[pos].l==tree[pos].r)
    {
        tree[pos].lson=tree[pos].rson=false;
        if(ch[l]=='0')
            tree[pos].store=1;
        else
            tree[pos].store=0;
        return;
    }
    tree[pos].lson=tree[pos].rson=true;
    int mid=(l+r)>>1;
    build(l,mid,pos*2);
    build(mid+1,r,pos*2+1);
    tree[pos].store=tree[pos*2].store+tree[pos*2+1].store;
}
void downtree(int i)
{
    tree[i].flag=false;
    tree[i].store=(tree[i].len-tree[i].store);
    if(tree[i].lson)    tree[i*2].flag=!tree[i*2].flag;
    if(tree[i].rson)    tree[i*2+1].flag=!tree[i*2+1].flag;
}
int find(int i)
{
    if(tree[i].flag)    downtree(i);
    if(tree[i].l==tree[i].r)
    {
        return tree[i].l;
    }
    if(tree[i].lson&&tree[i*2].flag) downtree(i*2);
    if(tree[i].lson&&tree[i*2].store) return find(i*2);
    else    return find(i*2+1);
}
void Update(int i,int from,int to)
{
    if(from<=tree[i].l&&tree[i].r<=to)
    {
        tree[i].flag=!tree[i].flag;
        return;
    }
    if(tree[i].flag)    downtree(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(to<=mid)
        {Update(i*2,from,to);}
    else if(from>=mid+1)
        {Update(i*2+1,from,to);}
    else
    {
        Update(i*2,from,to);
        Update(i*2+1,from,to);
    }
    if(tree[i*2].flag)  downtree(i*2);
    if(tree[i*2+1].flag)    downtree(i*2+1);
    tree[i].store=tree[i*2].store+tree[i*2+1].store;
}
int main()
{
    int n,k,tot,flag,i,from,to;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0)  break;
        scanf("%s",ch+1);
        tot=0;flag=1;
        if(k==0)
        {
            for(i=1;i<=n;i++)
                if(ch[i]=='0')
                {
                        break;
                }
            if(i!=n+1)
            {
                printf("-1\n");
                continue;
            }
        }
        if(k==1)
        {
            for(i=1;i<=n;i++)
                if(ch[i]==0)
                    tot++;
            printf("%d\n",tot);
                continue;
        }
        build(1,n,1);
        while(tree[1].store>0)
        {
            from=find(1);
            if(from+k-1>n)
            {
                flag=0;
                break;
            }
            Update(1,from,from+k-1);
            tot++;
        }
        if(flag)
        printf("%d\n",tot);
        else
        printf("-1\n");

    }
    return 0;
}


题意:有一个神奇的开关,能把k范围内的0->1 1->0,问最少需要多少个这样的开关,让整个序列变成全1.

因为是跟集合操作有关的,所以想到用线段树。

(1)在建树的时候设一个翻转标记位,更新的时候翻转。

(2)一共三个函数,一个用来翻转,一个用来寻找第一个0位置,一个用来更新(更新从头开始)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值