51Nod - 2014 小朋友的笑话 (动态开点 线段合并)

题目链接:传送门

题目思路:对于每一个笑话,用动态开点线段树来维护区间是否被覆盖(笑话是否已经被这些人听过),先假定范围内全部没听过(置1),然后再将该范围包含的被覆盖的区间置0;

(也可以用set存一下二元组表示线段左右端点,每次二分查询暴力合并)

代码:

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
typedef pair<double,double> pdd;
const int N=1e6+5;
const int M=2e5+5;
const int inf=1e8+5;
const LL mod=1e9+7;
const double eps=1e-8;
const long double pi=acos(-1.0L);
#define ls (i<<1)
#define rs (i<<1|1)
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define mk make_pair
#define mem(a,b) memset(a,b,sizeof(a))
LL read()
{
    LL x=0,t=1;
    char ch;
    while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
    while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
    return x*t;

}
struct node
{
    int l,r,v;
};
node c[N<<3];
int cnt,rt[N],t[N<<2],lz[N<<2],n,m;
void pushdown(int i,int l,int r)
{
    int mid=l+r>>1;
    lz[ls]=lz[rs]=lz[i];
    t[ls]=lz[i]*(mid-l+1);
    t[rs]=lz[i]*(r-mid);
    lz[i]=-1;
}
void update(int &now,int l,int r,int ll,int rr)
{
    if(now==0) now=++cnt;
    if(c[now].v) return ;
    if(ll<=l&&r<=rr) return (void)(c[now].v=1);
    int mid=l+r>>1;
    if(mid>=ll) update(c[now].l,l,mid,ll,rr);
    if(mid<rr) update(c[now].r,mid+1,r,ll,rr);
    c[now].v=min(c[c[now].l].v,c[c[now].r].v);
}
int query(int i,int l,int r,int ll,int rr)
{
    if(ll<=l&&r<=rr) return t[i];
    if(lz[i]!=-1) pushdown(i,l,r);
    int mid=l+r>>1,t1=0,t2=0;
    if(mid>=ll) t1=query(ls,l,mid,ll,rr);
    if(mid<rr) t2=query(rs,mid+1,r,ll,rr);
    return t1+t2;
}
void change(int i,int l,int r,int ll,int rr,int x)
{
    //printf("x = %d , l = %d , r = %d\n",x,l,r);
    if(ll<=l&&r<=rr) return (void)(t[i]=x*(r-l+1),lz[i]=x);
    if(lz[i]!=-1) pushdown(i,l,r);
    int mid=l+r>>1;
    if(mid>=ll) change(ls,l,mid,ll,rr,x);
    if(mid<rr) change(rs,mid+1,r,ll,rr,x);
    t[i]=t[ls]+t[rs];
}
void ask(int now,int l,int r,int ll,int rr)
{
    if(now==0) return ;
    if(c[now].v)
    {
        change(1,1,n,max(ll,l),min(rr,r),0);
        return ;
    }
    if(ll<=l&&r<=rr&&c[now].v)
    {
        change(1,1,n,l,r,0);//printf("l = %d , r = %d\n",l,r);
        return ;
    }
    int mid=l+r>>1;
    if(mid>=ll) ask(c[now].l,l,mid,ll,rr);
    if(mid<rr) ask(c[now].r,mid+1,r,ll,rr);
}
int main()
{
    mem(lz,-1);
    n=read(),m=read();
    while(m--)
    {
        int op=read();
        if(op==1){
            int l=read(),x=read(),k=read();
            change(1,1,n,max(1,l-k),min(n,l+k),1);
            ask(rt[x],1,n,max(1,l-k),min(n,l+k));
            update(rt[x],1,n,max(1,l-k),min(n,l+k));
            //printf("x = %d, rt = %d\n",x,rt[x]);
        }
        else{
            int l=read(),r=read();
            printf("%d\n",query(1,1,n,l,r));
        }
    }
    return 0;
}
View Code

 

posted @ 2021-04-10 20:58  DeepJay  阅读(59)  评论(0编辑  收藏  举报