P5524 Ynoi2012 NOIP2015 充满了希望

P5524 Ynoi2012 NOIP2015 充满了希望

数组开大见祖宗。

思路

利用“插入-标记-回收”这套处理函数复合的算法。

不难发现只有询问才会产生贡献,而询问的值来自于距离它最近的且能覆盖这个询问的点的覆盖操作。

可以每个询问操作保存一个 pre 指向能给这个查询位置赋值的最近的一次覆盖操作的编号。

只有 pre 在我们的操作序列中,这个位置的查询才可以有贡献(贡献就是覆盖操作赋的值)。

我们把操作离线,按左端点从大到小排序,每次在位置 i 加入大于当前左端点的 prei 的贡献。

然后区间查询 [l,r] 中贡献的和。

pre 可以用线段树维护,区间和可以用树状数组维护,总复杂度 O(nlogn)

CODE

#include<bits/stdc++.h>
using namespace std;

#define lch(p) p*2
#define rch(p) p*2+1
#define ll long long
#define se second
#define fi first

const int maxn=1e6+5;

inline int read()
{
    int a;
	int s = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	a = s * w;
    return a;
}
namespace linetree
{
    struct treenode{int lazy,num,l,r;}tr[maxn*4];
    inline void push_down(int p)
    {
        if(tr[p].l==tr[p].r&&tr[p].lazy!=-1) tr[p].num=tr[p].lazy,tr[p].lazy=-1;
        else if(tr[p].lazy!=-1)
        {
            tr[lch(p)].lazy=tr[lch(p)].num=tr[p].lazy;
            tr[rch(p)].lazy=tr[rch(p)].num=tr[p].lazy;
            tr[p].lazy=-1;
        }
    }
    inline void build(int p,int l,int r)
    {
        tr[p].l=l,tr[p].r=r;
        tr[p].lazy=-1;
        if(l==r) return ;
        int mid=(l+r)>>1;
        build(lch(p),l,mid),build(rch(p),mid+1,r);
    }
    inline void change(int p,int l,int r,int lx,int rx,int num)
    {
        if(l>rx||r<lx) return ;
        push_down(p);
        if(lx<=l&&r<=rx){tr[p].lazy=num;return ;}
        int mid=(l+r)>>1;
        change(lch(p),l,mid,lx,rx,num);change(rch(p),mid+1,r,lx,rx,num);
    }
    inline int qry(int p,int l,int r,int pos)
    {
        push_down(p);
        if(l==r) return tr[p].num;
        int mid=(l+r)>>1;
        if(pos<=mid) return qry(lch(p),l,mid,pos);
        else return qry(rch(p),mid+1,r,pos);
    }
}
struct treearray
{
    #define N 1e6
    ll ts[maxn];
    inline int lowbit(int x){return x&(-x);}
    inline void updata(int x,int y){for(;x<=N;x+=lowbit(x)) ts[x]+=y;}
    inline ll getsum(int x){ll sum=0;for(;x;x-=lowbit(x)) sum+=ts[x];return sum;}
}T;

int n,m,q;
int pre[maxn],val[maxn];

ll ans[maxn];

struct node{int l,r,id;}qr[maxn];

priority_queue< pair<int,pair<int,int>> >que;

inline bool cmp(node a,node b){return a.l>b.l;}

signed main()
{
    n=read(),m=read(),q=read();
    linetree::build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int op,l,r,x;
        op=read();
        if(op==1)
        {
            l=read(),r=read();
            int pl=linetree::qry(1,1,n,l),pr=linetree::qry(1,1,n,r);
            linetree::change(1,1,n,l,l,pr);
            linetree::change(1,1,n,r,r,pl);
        }
        else if(op==2)
        {
            l=read(),r=read(),x=read();
            linetree::change(1,1,n,l,r,i);
            val[i]=x;
        }
        else
        {
            // scanf("%d",&x);
            x=read();
            pre[i]=linetree::qry(1,1,n,x);
            val[i]=val[pre[i]];
            que.push({pre[i],{i,val[i]}});
        }
        // for(int j=1;j<=n;j++) cout<<linetree::qry(1,1,n,j)<<" ";
        // cout<<"\n";
    }
    for(int i=1;i<=q;i++)
    {
        qr[i].l=read(),qr[i].r=read();
        qr[i].id=i;
    }
    sort(qr+1,qr+q+1,cmp);
    for(int i=1;i<=q;i++)
    {
        while(!que.empty())
        {
            if(que.top().fi>=qr[i].l) T.updata(que.top().se.fi,que.top().se.se),que.pop();
            else break;
        }
        ans[qr[i].id]=T.getsum(qr[i].r)-T.getsum(qr[i].l-1);
    }
    for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
}

微卡常,须快读。

posted @   彬彬冰激凌  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示