zoukankan      html  css  js  c++  java
  • #树状数组,倍增#洛谷 6859 蝴蝶与花

    题目


    分析

    考虑以第一个开头的前缀如果存在那么一定存在长度为(s)(s+1)的路径和
    那么要想消掉多去的1就得找到一个更短的连续2然后减去最近的1,这可以用树状数组单log维护


    代码

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    const int N=2000011;
    int n,m,c[N],sum,a[N],two[21];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline void update(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
    inline signed query(int x){
    	rr int ans=0;
    	for (;x;x-=-x&x) ans+=c[x];
    	return ans;
    }
    inline signed answ(int s){
    	rr int ans=0,now=0;
    	for (rr int i=20;~i;--i)
    	if (ans+two[i]<=n&&now+c[ans+two[i]]<s)
    	    ans+=two[i],now+=c[ans];
    	return ans+1;
    }
    inline signed get_two(int x){
    	rr int now=0,ans=0,t=query(x-1);
    	for (rr int i=20;~i;--i)
    	if (ans+two[i]<x||(ans+two[i]<=n&&now+c[ans+two[i]]-t==(ans+two[i]-x+1)*2))
    	    ans+=two[i],now+=c[ans];
    	return ans;
    }
    signed main(){
    	n=iut(),m=iut(),two[0]=1;
    	for (rr int i=1;i<21;++i) two[i]=two[i-1]<<1;
    	for (rr int i=1;i<=n;++i) a[i]=iut(),c[i]=c[i-1]+a[i];
    	sum=c[n]; for (rr int i=n;i;--i) c[i]-=c[i&(i-1)];
    	for (rr int i=1;i<=m;++i){
    		rr char c=getchar();
    		while (!isalpha(c)) c=getchar();
    		if (c=='C'){
    			rr int x=iut(),y=iut();
    			update(x,y-a[x]),
    			sum+=y-a[x],a[x]=y;
    		}else{
    			rr int s=iut(),t,now;
    			if (!s||s>sum) {printf("none
    "); continue;}
    			t=answ(s),now=query(t);
    			if (now==s) {print(1),putchar(32),print(t),putchar(10); continue;}
    			rr int cnt1=get_two(1),cnt2=get_two(t)-t+1;
    			if (cnt1>=cnt2){
    				if (t+cnt2>n) printf("none
    ");
    				    else print(1+cnt2),putchar(32),print(t+cnt2),putchar(10); 
    			}else{
    				if (t+cnt1>n) printf("none
    ");
    				    else print(2+cnt1),putchar(32),print(t+cnt1),putchar(10); 				
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java中的break和continue关键字使用总结
    Java Foreach语句使用总结
    Android的线程(Thread)和服务(Service)的区别
    Android终止无限循环线程和程序退出时销毁线程
    IoC(Inversion of Control,控制反转)模式
    浅谈手机app测试注意点
    Android获取手机相关信息
    深搜
    5种排序方式
    一个简单的文本编辑器
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13922304.html
Copyright © 2011-2022 走看看