今天码力不足还有点丧,不应该这样哦,学习新东西应该是一件很开心的事情。
昨天学的一种优美的暴力方法,分块。
找了个题试试这个方法,结果优化失败T掉了,主要就是最后没有想到逆序求f数组与to数组,
因为前面的值可以通过后面的值推出的,简单加一就好。
一开始只能想到直接顺序暴力求f还有更新,被卡掉了。
日常感叹我好菜呀

Bounce 弹飞绵羊

VJ题目链接:https://vjudge.net/problem/HYSBZ-2002
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=2e5+10;
#define pi   acos(-1.0)
#define INF   0x3f3f3f3f
#define mod   1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n,m,block;
int k[MAXN];
int pos[MAXN];//
int f[MAXN];//从一个点出发跳出所在块所需要的步数
int to[MAXN];//从一个点出发跳出块后到达哪
int query(int x)
{
    int ans=0;
    for(int i=x;i<=n;i=to[i])
        ans+=f[i];
    return ans;
}
void update(int x,int v)
{
    k[x]=v;
    for(int i=x;i>=(pos[x]-1)*block+1;i--)
    {
        if(i+k[i]>pos[i]*block||i+k[i]>n)
        {
            f[i]=1;
            to[i]=i+k[i];
        }
        else
        {
            f[i]=f[i+k[i]]+1;
            to[i]=to[i+k[i]];
        }
    }
}
int main()
{
    while(~s1(n))
    {
        // init
        for(int i=1;i<=n;i++) s1(k[i]);
        block=sqrt(n);
        for(int i=1;i<=n;i++)
            pos[i]=(i-1)/block+1;
        for(int i=n;i>=1;i--)//怎么就想不到前面的步数可以用后面的步数+1,T哭
        {
            if(i+k[i]>pos[i]*block||i+k[i]>n)
            {
                f[i]=1;
                to[i]=i+k[i];
            }
            else
            {
                f[i]=f[i+k[i]]+1;
                to[i]=to[i+k[i]];
            }
        }
//        for(int i=1;i<=n;i++)
//            printf("pos[%d]=%d f[%d]=%d to[%d]=%d\n",i,pos[i],i,f[i],i,to[i]);
        int m;s1(m);
        while(m--)
        {
            int i,j,v;
            s1(i);
            if(i==1)
            {
                s1(j);
                j++;
                printf("%d\n",query(j));
            }
            else
            {
                s2(j,v);
                j++;
                update(j,v);
            }
        }
    }
    return 0;
}

P2801 教主的魔法

洛谷题目链接:https://www.luogu.org/problem/P2801
大概是个分块水题,主要涉及的就是区间修改和区间查询
暴力分块加二分查找,然而T掉了,找了找博客感觉思路没差,,,
学过分块之后做了两个题都T掉了,,,我没掌握到精髓。
明天再改一下代码吧。
/19/8/2
改了一小时,,,终于给过了
原来T掉是因为自己代码写的太丑,,,很多边界闭着眼码都码错了。
边界改好后又开始蛙,因为二分没写对。
写码还是仔细点八。
/19/8/3
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e6+10;
#define pi   acos(-1.0)
#define INF   0x3f3f3f3f
#define mod   1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n,m,q,block;//m块数
int h[MAXN];//原数组
int f[MAXN];//分块排序之后的数组
int pos[MAXN];
int lazy[MAXN];//某块中的操作值
void reset(int x)//更新某块
{
    int l=(x-1)*block+1,r=min(x*block,n);
    for(int i=l;i<=r;i++)
        f[i]=h[i];
    sort(f+l,f+r+1);
}
void update(int l,int r,int w)
{
    if(pos[l]==pos[r])
    {
        for(int i=l;i<=r;i++) h[i]+=w;
    }
    else
    {
        for(int i=l;i<=pos[l]*block;i++) h[i]+=w;
        for(int i=(pos[r]-1)*block+1;i<=r;i++) h[i]+=w;
    }
    reset(pos[l]);
    reset(pos[r]);
    for(int i=pos[l]+1;i<pos[r];i++)
        lazy[i]+=w;
}
int query(int l,int r,int w)
{
    int ans=0;
    if(pos[l]==pos[r])
    {
        for(int i=l;i<=r;i++)
            if(h[i]+lazy[pos[i]]>=w)
                ans++;
    }
    else
    {
        for(int i=l;i<=pos[l]*block;i++)
            if(h[i]+lazy[pos[i]]>=w)
                ans++;
        for(int i=(pos[r]-1)*block+1;i<=r;i++)
            if(h[i]+lazy[pos[i]]>=w)
                ans++;
    }
    for(int k=pos[l]+1;k<pos[r];k++)
    {
        int l=(k-1)*block+1,r=min(k*block,n);
        r++;//左开右闭右边界记得处理啊。。
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(f[mid]+lazy[k]>=w)
                r=mid;
            else
                l=mid+1;
        }
        ans+=min(k*block,n)-l+1;
    }
//闭区间写法
//    for(int k=pos[l]+1;k<pos[r];k++)
//    {
//        int l=(k-1)*block+1,r=min(k*block,n);
//        while(l<=r)
//        {
//            int mid=(l+r)>>1;
//            if(f[mid]+lazy[k]>=w)
//                r=mid-1;
//            else
//                l=mid+1;
//        }
//        ans+=min(k*block,n)-l+1;
//    }
    return ans;
}
int main()
{
    s2(n,q);
    block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        s1(h[i]);
        pos[i]=(i-1)/block+1;
    }
    m=n/block+(n%block!=0);
    for(int i=1;i<=m;i++)
        reset(i);
    while(q--)
    {
        char s[5];
        int l,r,w;
        scanf("%s",s);
        s3(l,r,w);
        if(s[0]=='M')
            update(l,r,w);
        else
            printf("%d\n",query(l,r,w));
    }
    return 0;
}