洛谷P6783 [Ynoi2008] rrusq

先将询问离线,从小到大扫描右端点并维护左端点的答案。让每个关键点在能覆盖它的矩形中编号最大一个有贡献,每次询问就是查询矩形对应的区间贡献和。

每次右端点移动时,考虑新加入的矩形覆盖的点集,将该点集有贡献的位置修改为当前的右端点。这一过程可以用 \(K-D\ Tree\) 来维护,暴力回收子树内的标记,复杂度仍是正确的,因为回收标记时之前已经有打标记的复杂度了。

一共有 \(O(m\sqrt n)\) 次单点修改和 \(O(q)\) 次区间查询,因此用分块来维护,总复杂度为 \(O\left(m\sqrt n+q\sqrt m\right)\)

#include<bits/stdc++.h>
#define maxn 1000010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,q,S,root,tot,type;
int ans[maxn],bel[maxn],a[maxn],add[maxn];
vector<pair<int,int> > ve[maxn];
struct tree
{
    int d[2],mx[2],mn[2],ls,rs,val,sum,tim,tag,vis;
}t[maxn],dat[maxn];
bool cmp(const tree &a,const tree &b)
{
    return a.d[type]<b.d[type];
}
struct matrix
{
    int u,d,l,r;
}mt[maxn];
void update(int x,int v)
{
    a[x]+=v,add[bel[x]]+=v;
}
int ask(int x)
{
    int v=0;
    for(int i=x;i<=min(S*bel[x],m);++i) v+=a[i];
    for(int i=bel[x]+1;i<=bel[m];++i) v+=add[i];
    return v;
}
void pushup(int x)
{
    int ls=t[x].ls,rs=t[x].rs;
    for(int i=0;i<=1;++i)
    {
        t[x].mx[i]=t[x].mn[i]=t[x].d[i];
        if(ls)
        {
            t[x].mx[i]=max(t[x].mx[i],t[ls].mx[i]);
            t[x].mn[i]=min(t[x].mn[i],t[ls].mn[i]);
        }
        if(rs)
        {
            t[x].mx[i]=max(t[x].mx[i],t[rs].mx[i]);
            t[x].mn[i]=min(t[x].mn[i],t[rs].mn[i]);
        }
    }
    t[x].sum=t[ls].sum+t[rs].sum+t[x].val;
}
void del(int x)
{
    if(t[x].tag) update(t[x].tag,-t[x].sum),t[x].tag=t[x].tim=0;
    if(t[x].tim) update(t[x].tim,-t[x].val),t[x].tim=0;
}
void pushdown(int x)
{
    if(!t[x].tag) return;
    int ls=t[x].ls,rs=t[x].rs;
    del(ls),del(rs),t[ls].tag=t[ls].tim=t[rs].tag=t[rs].tim=t[x].tag;
    t[ls].vis=t[rs].vis=1,t[x].tag=0;
}
void build(int l,int r,int k,int &x)
{
    x=++tot,type=k;
    int mid=(l+r)>>1;
    nth_element(dat+l+1,dat+mid+1,dat+r+1,cmp),t[x]=dat[mid];
    if(l<mid) build(l,mid-1,k^1,t[x].ls);
    if(r>mid) build(mid+1,r,k^1,t[x].rs);
    pushup(x);
}
bool check(int x,int p)
{
    return mt[p].u<=t[x].d[0]&&mt[p].d>=t[x].d[0]&&mt[p].l<=t[x].d[1]&&mt[p].r>=t[x].d[1];
}
bool in(int x,int p)
{
    return mt[p].u<=t[x].mn[0]&&mt[p].d>=t[x].mx[0]&&mt[p].l<=t[x].mn[1]&&mt[p].r>=t[x].mx[1];
}
bool out(int x,int p)
{
    return mt[p].u>t[x].mx[0]||mt[p].d<t[x].mn[0]||mt[p].l>t[x].mx[1]||mt[p].r<t[x].mn[1];
}
void clear(int x)
{
    if(!x||!t[x].vis) return;
    del(x),clear(t[x].ls),clear(t[x].rs),t[x].vis=0;
}
void modify(int x,int p)
{
    if(!x||out(x,p)) return;
    if(in(x,p))
    {
        clear(x),update(t[x].tag=t[x].tim=p,t[x].sum),t[x].vis=1;
        return;
    }
    if(check(x,p)) update(t[x].tim,-t[x].val),update(t[x].tim=p,t[x].val);
    pushdown(x),t[x].vis=1,modify(t[x].ls,p),modify(t[x].rs,p);
}
int main()
{
    read(n);
    for(int i=1;i<=n;++i)
        read(dat[i].d[1]),read(dat[i].val),dat[i].d[0]=i;
    read(m),S=sqrt(m);
    for(int i=1;i<=m;++i)
        bel[i]=(i-1)/S+1,read(mt[i].u),read(mt[i].d),read(mt[i].l),read(mt[i].r);
    read(q);
    for(int i=1,l,r;i<=q;++i)
        read(l),read(r),ve[r].push_back(make_pair(l,i));
    build(1,n,0,root);
    for(int i=1;i<=m;++i)
    {
        modify(root,i);
        for(int j=0;j<ve[i].size();++j)
            ans[ve[i][j].second]=ask(ve[i][j].first);
    }
    for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2021-01-24 20:24  lhm_liu  阅读(236)  评论(0编辑  收藏  举报