HDU 3450 线段树+二分

点击打开链接

题意:给一个数字序列,问你长度大于2的且相邻两个数的差的绝对值不大于d的情况对9901取余

思路:看了根本不会,都没想到是线段树的题目,弱哭~~~,看了大牛们的题解,算是知道怎么回事了,对于当前的数A,那么以它为最后一个元素可以组成的情况是A-d到A+d的和,也可以这样想,A-d的已经组成了m种情况,那么在不影响小于d的情况下,可以直接将A放到A-d组成的左右序列中,那么直接加就可以了,而后更新A可以组成的情况,数据太大还需要离散化,然后二分找一下A-d和A+d的位置,数据可能没有这两个位置,那么找到第一个大于等于A-d和第一个小于等于A+d的位置更新就行,且不会影响结果,自己写个数据看看就会懂了
   PS:多校的题目好难,想着一天刷一套自己部分的题目,而且太难的直接放弃(毕竟太弱),还是有点难以完成啊

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=100010;
const int mod=9901;
int num[maxn<<2],A[maxn],B[maxn];
int n,m;
int lower_1(int val,int k){
    int le=0,ri=k;
    while(ri-le>1){
        int mid=(le+ri)>>1;
        if(B[mid]<=val) le=mid;
        else ri=mid;
    }
    return le+1;
}
void update(int pos,int add,int le,int ri,int node){
    if(le==ri){
        num[node]+=add;
        num[node]%=mod;
        return ;
    }
    int t=(le+ri)>>1;
    if(pos<=t) update(pos,add,le,t,node<<1);
    else update(pos,add,t+1,ri,node<<1|1);
    num[node]=(num[node<<1]+num[node<<1|1])%mod;
}
int query(int l,int r,int le,int ri,int node){
    if(l<=le&&ri<=r) return num[node];
    int ans=0,t=(le+ri)>>1;
    if(l<=t) ans+=query(l,r,le,t,node<<1);
    if(r>t) ans+=query(l,r,t+1,ri,node<<1|1);
    return ans%mod;
}
int main(){
    while(scanf("%d%d",&n,&m)!=-1){
        int k=1,ans=0;
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++){
            scanf("%d",&A[i]);
            B[i]=A[i];
        }
        sort(B,B+n);
        for(int i=1;i<n;i++){
            if(B[i]!=B[i-1]) B[k++]=B[i];
        }
        for(int i=0;i<n;i++){
            int le=lower_bound(B,B+k,A[i]-m)-B+1;
            int ri=lower_1(A[i]+m,k);
            int pos=lower_bound(B,B+k,A[i])-B+1;
            int ans1=query(le,ri,1,k,1);
            ans=(ans+ans1)%mod;
            update(pos,ans1+1,1,k,1);
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-07 19:52:25

HDU 3450 线段树+二分的相关文章

hdu 6070 线段树+二分

HDU - 6070 题意:提交了n次题目,每个题目都是最后一次提交的时候AC的,现在求一个区间,这个区间的AC率是最低的(只考虑这个区间内的题目,同样区间内最后交的一遍是AC的),求最低的AC率 思路:AC率=提交次数/题目数目,即区间长度/题目种类,siz[l,r]/(r-l+1)=p(siz[l,r]表示l r区间内的不同题目的个数,p表示AC率), 把式子做一下调整,siz[l,r]+p*l=p(r+1),二分p(0-1)用线段树维护siz[l,r]+l*p ,然后枚举r,每次更新,因为

hdu 4339 线段树+二分

题意是给你两个字符串    进行两种操作   1: 修改其中一个字符串里的某个字符2:   询问从i起两个字符串最多由多少个是相同的: 先说一下做之前的想法   ,我是看别人介绍树状数组是看到这道题的    本也想用树状数组做  ,没想上去    然后就改为线段树了   ,有很明显的点更新,区间查询,所以选择线段树: 思路:  每个节点num[] 存3个值       p1  p2  flash   flash表示当前节点两个字符串是不是一样的   若是则为1否则为0    p1 p2为当前两个

hdu 4614 线段树 二分

题意:有n个花瓶,每个花瓶中只能放一朵花. 两种操作,一种是从A开始放F朵花,如果有的花瓶中已经有花则跳过这个花瓶,往下一个花瓶放: 输出这次放的花的左右端点.如果能放但是放不完f朵输出n就好了 第二种是将区间[A,B]之间花瓶中的花清空.输出这次总共清理出了多少支花. 思路:第二种很明显可以用线段树实现,问题在第一种如何用线段树实现 用二分  和 线段树 来判断右端点的位置  这样就可以了  第一次操作就成了区间更新 并且查询左右端点 #include<cstdio> #include<

hdu 4893 (多校1007)Wow! Such Sequence!(线段树&amp;二分&amp;思维)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 352    Accepted Submission(s): 104 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

hdu 5592 ZYB&#39;s Premutation (线段树+二分查找)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=5592 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to  restore the premutation.Pair (i,j)(i<j) is considered as a reverse

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

HDU 4417 划分树+二分

题意:有n个数,m个询问(l,r,k),问在区间[l,r] 有多少个数小于等于k. 划分树--查找区间第k大的数.... 利用划分树的性质,二分查找在区间[l,r]小于等于k的个数. 如果在区间第 i 大的数tmp>k,则往下找,如果tmp<k,往上找. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #incl

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a