hdu 3275 Light 很好很好的线段树 收获丰富

Light

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 707    Accepted Submission(s): 224


Problem Description
Felicia was given a long string of fancy lanterns, but not all of them are on to light the night. Felicia felt bad about that and he wants to light up all the lanterns. There is a kind of magic switch which can change the states of k continuous lanterns. Once you choose k continuous lanterns and install a switch on them, the states of all k continuous lanterns can be changed together (on ->off or off ->on), but you cannot choose some ones be changed and some ones not be changed.
Felicia wants to buy as few switches as possible so that he can install them to turn on all the lanterns. Please notice that each switch must control exactly k continuous lanterns.
 

Input
The input consists of multiple test cases. The first line of each case contains integers n(0 < n <= 100000), which is the length of that string of fancy lanterns, and k(0 <= k <= n), which is the number of continuous lanterns that a switch will control. The next line consists of a string of “01” with length n. “1” means that lantern is on and “0” means off. Your job is turn all the “0” to “1”.
The last test case is followed by a line containing two zeros.
 

Output
If you cannot finish this job, output “-1” or you should output the minimum number switches that you should buy to turn on all the lanterns.
 

Sample Input
  
  
4 2 0000 4 2 1001 4 2 0110 4 2 0111 0 0
 

Sample Output
  
  
2 1 3 -1

题意:

输入n k 

以及n个0或1 

问把串全部转化为1 每步会把从pos开始的第k个全部更改为相反的状态  至少需要多少步 如果无法全部变为1 则输-1


思路:   写几组数据可以发现  从左往右遇到0就变为1 到最后全变为1   这样得出的就是最少的步骤


关键是如何迅速的找出有0的位置 这时候就要用线段树去标记一个段内是否有0了


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct haha
{
    int num1;
    int num0;
    int flag;
    int left;
    int right;
}node[100000*4];
char s[100000+100];
void build(int nd,int left,int right)
{
     node[nd].left=left;
     node[nd].right=right;
     node[nd].flag=0;
     if(node[nd].left==node[nd].right)
     {
         if(s[node[nd].left]=='1')
         {
             node[nd].num0=0;
             node[nd].num1=1;
         }
         else
         {
             node[nd].num1=0;
             node[nd].num0=1;
         }
             return ;
     }
     int mid=(left+right)/2;
     build(nd*2,left,mid);
     build(nd*2+1,mid+1,right);
     node[nd].num0=node[nd*2].num0+node[nd*2+1].num0;
     node[nd].num1=node[nd*2].num1+node[nd*2+1].num1;
}
void change(int nd)
{
       int temp;
       if(node[nd].left==node[nd].right) return ;
       temp=node[nd*2].num0;node[nd*2].num0=node[nd*2].num1;node[nd*2].num1=temp;
       temp=node[nd*2+1].num0;node[nd*2+1].num0=node[nd*2+1].num1;node[nd*2+1].num1=temp;
     //  node[nd].flag=0;node[nd*2].flag=1;node[nd*2+1].flag=1;//这样写是绝对错误的 因为这里 我错了10几遍啊 呜呜
	   node[nd].flag=!node[nd].flag;node[nd*2].flag=!node[nd*2].flag;//应该这样写 注意 以后都要这样规范的写
	   node[nd*2+1].flag=!node[nd*2+1].flag;//因为你不能保证一个不被标记2边 即子节点可能标记2边 

}
int query(int nd)
{
    if(node[nd].left==node[nd].right)  return node[nd].left;//==写成了=  一个劲的错 呜呜
    if(node[nd].flag) change(nd);
    int pos=-1;
    if(node[nd*2].num0) pos=query(nd*2);
    else
    if(node[nd*2+1].num0)  pos=query(nd*2+1);
     node[nd].num0=node[nd*2].num0+node[nd*2+1].num0;
     node[nd].num1=node[nd*2].num1+node[nd*2+1].num1;
    return pos;
 }
void update(int nd,int left,int right)
{
       int i,j,mid;
       if(node[nd].flag) change(nd);
       if(node[nd].left==left&&node[nd].right==right)
       {
           int temp;
           temp=node[nd].num0;node[nd].num0=node[nd].num1;node[nd].num1=temp;
           node[nd].flag=1;
           return ;
       }
       
       mid=(node[nd].left+node[nd].right)/2;
       if(right<=mid) update(nd*2,left,right);
       else if(left>mid) update(nd*2+1,left,right);
       else 
       {
           update(nd*2,left,mid);
           update(nd*2+1,mid+1,right);
       }
     node[nd].num0=node[nd*2].num0+node[nd*2+1].num0;
     node[nd].num1=node[nd*2].num1+node[nd*2+1].num1;
       return ;

}
int main()
{
    int n,k,i,j,flag,left,right,ans,num,len;

    while(scanf("%d %d",&n,&k)!=EOF)
    {
        flag=0;ans=0;num=0;
        if(!n&&!k) break;
        scanf("%s",s+1);//只要输入 不用再转化进一个int数组 否则会超时 所以不必要的操作一定不要要
		len=strlen(s+1);
		 build(1,1,len);
        for(i=1;i<=len;i++)
			if(s[i]=='0') {flag=1;break;}
        if(k==0)
        {
			if(node[1].num1==len) printf("0\n");
			else
             printf("-1\n");
            continue;
        }
		if(flag==0) {printf("0\n");continue;}
        int pos;//记录最左边0的位置
        flag=0;
        while(pos=query(1))
        {
              if(pos==-1) break;
              left=pos;right=pos+k-1;
              if(right>len) {printf("-1\n");flag=1;break;}
              update(1,left,right);
              ans++;
        }
        if(flag) continue;
        else printf("%d\n",ans);
    }
    return 0;
}


收获:  原来一些无用的小操作也能引起超时

另外 那些红色字体 很重要   以后直接按那种方式写好了  标准   


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值