题解 P4970 【全村最好的嘤嘤刀】

· · 题解

线段树(较简略)+模拟(最短但是没注释)

要不是和我老婆有关,我才不做呢(哼

这道题我一年前就发现了,模拟45pt,看到模拟题解后,我吃了一惊。。。为什么倒序循环能ACCEPT,而正序只有45pt?!自闭了
所以我吸氧的36行跑的那么快仅仅就改了个倒序循环。。。
几个坑点

但我们还是要来说一下线段树,其实线段树真的不好码。。。
因为我们不但要标记飞鱼丸,还有区间修改,最大值查询和单点修改

我找了好几道线段树才拼在一起的!

解释不多,相信您们都能看懂,我码了2个小时,12点啦,虚啦~

变量名有一半是我老婆哦!!!

#include <iostream>
#include <cstdio>
using namespace std;
int n,m,bcy=0,p,x,y,v;
//布狼牙/八重樱/琪亚娜
int blny[100000+100],qyn[100000*4+10];
//因为重载了max,所以延迟标记要单独出来
struct node{
    int maxx,max_place;
    friend node max(node a,node b) { return a.maxx>b.maxx ? a:b; }//重载max
}tree[100000*4+10];//存树 
void build(int l,int r,int num) // 标准建树 
{
    if(l==r)
    {
        cin >> tree[num].maxx;
        tree[num].max_place=l; 
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    tree[num]=max(tree[num<<1],tree[num<<1|1]);
}
//希儿
void xe(int l,int r,int num) //将某点清零 
{
    if(qyn[num])
    {
        int mid=(l+r)>>1;
        tree[num<<1].maxx+=qyn[num];
        tree[num<<1|1].maxx+=qyn[num];
        qyn[num<<1]+=qyn[num];
        qyn[num<<1|1]+=qyn[num];
        qyn[num]=0;
    }
}
//姬子
void jz(int l,int r,int L,int val,int num) 
//将这个飞鱼丸标记qwq 
{
    if(l==r)
    {
        tree[num].maxx=val-tree[num].maxx;
        return;
    }
    int mid=(l+r)>>1;
    xe(l,r,num);
    if(mid<L) jz(mid+1,r,L,val,num<<1|1);
    else jz(l,mid,L,val,num<<1);
    tree[num]=max(tree[num<<1],tree[num<<1|1]);
}
node ask(int l,int r,int L,int R,int num) //标准查询 
{
    if(l==L&&r==R) return tree[num];
    int mid=(l+r)>>1;
    xe(l,r,num);
    if(mid<L) return ask(mid+1,r,L,R,num<<1|1);
    else if(mid>=R) return ask(l,mid,L,R,num<<1);
    else return max(ask(l,mid,L,mid,num<<1),ask(mid+1,r,mid+1,R,num<<1|1));
}
void change(int l,int r,int L,int R,int val,int num) //标准区间修改 
{
    if(l==L&&r==R)
    {
        tree[num].maxx+=val;
        qyn[num]+=val;
        return;
    }
    int mid=(l+r)>>1;
    xe(l,r,num);
    if(mid<L) change(mid+1,r,L,R,val,num<<1|1);
    else if(mid>=R) change(l,mid,L,R,val,num<<1);
    else change(l,mid,L,mid,val,num<<1),change(mid+1,r,mid+1,R,val,num<<1|1);
    tree[num]=max(tree[num<<1],tree[num<<1|1]);
} 
void add(int x,int val) { for(;x<=n;x+=x&-x) blny[x]+=val;} 
//标准区间加 
int sum(int x) //标准区间求和 
{
    int ans=0;
    for(;x;x-=x&-x) ans+=blny[x];
    return ans;
}
int main()
{
    cin >> n >> m;
    build(1,n,1); //建树 
    while(m--)
    {
        cin >> p;
        if(p==1)
        {
            cin >> x >> v;
            jz(1,n,x,v,1); //标记飞鱼丸  
            add(x,x); //嘤嘤嘤能量变
        }
        if(p==2)
        {
            cin >> x >> y;
            int num=sum(y)-sum(x-1);//飞鱼丸 
            if(num)
            {
                node ans=ask(1,n,num,num,1); 
                printf("%d\n",ans.maxx);
                bcy += ans.maxx; //获得能量++ 
                change(1,n,num,num,-ans.maxx,1); 
                //牵一发而动全身 
                add(num,-num);
                continue;
            }
            node ans=ask(1,n,x,y,1);//最大点 
            change(1,n,ans.max_place,ans.max_place,-ans.maxx,1);
            printf("%d\n",ans.maxx);
            bcy += ans.maxx;//同上了qwq 
        }
        if (p == 3) 
        {
            cin >> x >> y >> v; 
            change (1,n,x,y,v,1); //区间修改 
        }
    }
    if(bcy<10000) printf("QAQ");
    else  if(bcy<10000000) printf("Sakura");
    else printf("ice");
    return 0;
}

附36行小模拟这最多也就是个黄题吧
倒序太坑人了CRY

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,num,l,r,val,now,x,a[100005],ans;
bool b[100005];
int main()
{
    cin >> n >> m;
    for ( int i = 1; i <= n; i++ ) cin >> a[i];
    while (m--)
    {
        cin >> num;
        if ( num == 1 ) cin >> x >> val , a[x] = val-a[x],b[x] = 1;
        if ( num == 2 )
        {
            cin >> l >> r , val = 0;
            for ( int i = r; i >= l; i-- )
            {
                if (b[i]) { now = i , b[i] = 0 , val = a[i]; break; }
                if (val < a[i]) now = i , val = a[i];
            }
            a[now] = 0 , ans += val;
            cout << val << endl;
        }
        if ( num == 3 )
        {
            cin >> l >> r >> val;
            for ( int i = l; i <= r; i++ ) a[i] += val;
        }
    }
    if (ans<10000) cout<<"QAQ";
    if (ans>=10000&&ans<10000000) cout<<"Sakura";
    if (ans>=10000000) cout<<"ice";
    return 0;
}

实际证明,线段树比模拟共快了400ms!
算了,以后就只打暴力了
谢谢观赏