COJ WZJ的数据结构(负三十三)

WZJ的数据结构(负三十三)
难度级别:E; 运行时间限制:7000ms; 运行空间限制:262144KB; 代码长度限制:2000000B

试题描述

请你设计一个数据结构,完成以下功能:

给定一个大小为N的整数组A,要求你回答执行N次操作。操作分两种:

操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数。

操作2:每次操作给你l,r,v三个参数,将Al至Ar所有数的值设为v。


输入

第一行为一个正整数N。
第二行为N个整数Ai。
接下来N行每行4个正整数t,l,r,v。若t=2表示操作1,t=1表示操作2。

输出

对每个操作1输出结果。

输入示例

6
1 2 2 1 2 3
2 1 4 2
2 1 4 1
1 2 4 1
2 1 4 1
1 3 5 2
2 2 5 2

输出示例

4
2
4
4

其他说明

1<=N<=200000
1<=Ai,v<=10^9

XYZ大爷论文题“一个简单的序列问题”。

一上午的青春全部奉献给这道题了(3棵线段树调得我要报警)。

先将区间修改转化成带删除的区间插入,用一棵线段树来做。

再用线段树分治将问题转化成静态问题,用一棵线段树和2个nlogn的邻接表。

最后排序后转化成区间加与区间查询的问题,用一棵线段树来做。

说起来真是简单呢!

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int maxn=400010;
struct Query {
    int tp,l,r,x,begin,end,id;
    bool operator < (const Query& ths) const {return begin<ths.begin;}
}Q[maxn],Q2[maxn*3];
struct Solver {
    int id,l,r,x;
    bool operator < (const Solver& ths) const {return x<ths.x||(x==ths.x&&id<ths.id);}
}A[maxn*3];
int n,ans[maxn],m;
int setv[maxn*3],is[maxn*3];
void pushdown(int o) {
    int lc=o<<1,rc=lc|1;
    if(setv[o]) {
        setv[lc]=setv[rc]=setv[o];
        is[lc]=is[rc]=1;
        setv[o]=0;
    }
}
int lastv,L,R;
void find(int o,int l,int r,int v) {
    if(!is[o]) return;
    if(setv[o]) {
        if(setv[o]==lastv) R=r;
        else {
            if(lastv!=-1) Q2[++m]=(Query){1,L,R,Q[lastv].x,lastv,v-1,Q[lastv].id};
            lastv=setv[o];L=l;R=r;
        }
        setv[o]=0;
    }
    else if(l<r) {
        int mid=l+r>>1,lc=o<<1,rc=lc|1;
        find(lc,l,mid,v);find(rc,mid+1,r,v);
    }
    is[o]=0;
}
void update(int o,int l,int r,int ql,int qr,int v) {
    if(ql<=l&&r<=qr) find(o,l,r,v),setv[o]=v;
    else {
        pushdown(o);
        int mid=l+r>>1,lc=o<<1,rc=lc|1;
        if(ql<=mid) update(lc,l,mid,ql,qr,v);
        if(qr>mid) update(rc,mid+1,r,ql,qr,v);
    }
    is[o]=1;
}
int first1[maxn*3],next1[maxn*20],id1[maxn*20],ToT1;
int first2[maxn*3],next2[maxn*20],id2[maxn*20],ToT2,N;
void query(int o,int l,int r,int pos,int v) {
    N=max(N,o);
    id1[++ToT1]=v;next1[ToT1]=first1[o];first1[o]=ToT1;
    if(l==r) return;
    int mid=l+r>>1,lc=o<<1,rc=lc|1;
    if(pos<=mid) query(lc,l,mid,pos,v);
    else query(rc,mid+1,r,pos,v);
}
void modify(int o,int l,int r,int ql,int qr,int v) {
    N=max(N,o);
    if(ql<=l&&r<=qr) {
        id2[++ToT2]=v;next2[ToT2]=first2[o];first2[o]=ToT2;
    }
    else {
        int mid=l+r>>1,lc=o<<1,rc=lc|1;
        if(ql<=mid) modify(lc,l,mid,ql,qr,v);
        if(qr>mid) modify(rc,mid+1,r,ql,qr,v);
    }
}
int addv[maxn*3],sumv[maxn*3];
void pushdown2(int o,int l,int r) {
    int mid=l+r>>1,lc=o<<1,rc=lc|1;
    if(addv[o]) {
        addv[lc]+=addv[o];addv[rc]+=addv[o];
        sumv[lc]+=addv[o]*(mid-l+1);sumv[rc]+=addv[o]*(r-mid);
        addv[o]=0;
    }
}
void update2(int o,int l,int r,int ql,int qr,int v) {
    int mid=l+r>>1,lc=o<<1,rc=lc|1;
    if(ql<=l&&r<=qr) addv[o]+=v;
    else {
        pushdown2(o,l,r);
        if(ql<=mid) update2(lc,l,mid,ql,qr,v);
        if(qr>mid) update2(rc,mid+1,r,ql,qr,v);
    }
    if(l<r) sumv[o]=sumv[lc]+sumv[rc];
    else sumv[o]=0;
    if(addv[o]) sumv[o]+=addv[o]*(r-l+1);
}
int query2(int o,int l,int r,int ql,int qr) {
    if(ql<=l&&r<=qr) return sumv[o];
    pushdown2(o,l,r);
    int mid=l+r>>1,lc=o<<1,rc=lc|1,ans=0;
    if(ql<=mid) ans+=query2(lc,l,mid,ql,qr);
    if(qr>mid) ans+=query2(rc,mid+1,r,ql,qr);
    return ans;
}
int tmp[maxn];
int main() {
    n=read();
    rep(i,1,n) Q[Q[i].id=i].tp=1,Q[i].l=i,Q[i].r=i,Q[i].x=read();
    rep(i,n+1,2*n) Q[Q[i].id=i].tp=read(),Q[i].l=read(),Q[i].r=read(),Q[i].x=read();
    n<<=1;
    Q[n+1].tp=1;Q[n+1].l=1;Q[n+1].r=n>>1;
    rep(i,1,n+1) {
        if(Q[i].tp==1) {
            lastv=-1;
            update(1,1,n>>1,Q[i].l,Q[i].r,i);
            if(lastv!=-1) Q2[++m]=(Query){1,L,R,Q[lastv].x,lastv,i-1,Q[lastv].id};
        }
        else Q2[++m]=Q[i],Q2[m].begin=Q2[m].end=i;
    }
    rep(i,1,m) {
        if(Q2[i].tp==1) modify(1,1,n,Q2[i].begin,Q2[i].end,i);
        else query(1,1,n,Q2[i].begin,i);
    }
    rep(i,1,N) if(first1[i]&&first2[i]) {
        int cnt=0;
        for(int j=first1[i];j;j=next1[j]) A[++cnt]=(Solver){Q2[id1[j]].id,Q2[id1[j]].l,Q2[id1[j]].r,Q2[id1[j]].x};
        for(int j=first2[i];j;j=next2[j]) A[++cnt]=(Solver){0,Q2[id2[j]].l,Q2[id2[j]].r,Q2[id2[j]].x};
        sort(A+1,A+cnt+1);
        rep(j,1,cnt) {
            if(!A[j].id) update2(1,1,n>>1,A[j].l,A[j].r,1);
            else ans[A[j].id]+=query2(1,1,n>>1,A[j].l,A[j].r);
        }
        rep(j,1,cnt) if(!A[j].id) update2(1,1,n>>1,A[j].l,A[j].r,-1);
    }
    rep(i,1,n) if(Q[i].tp==2) printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-08-01 15:18:25

COJ WZJ的数据结构(负三十三)的相关文章

COJ 0967 WZJ的数据结构(负三十三)

WZJ的数据结构(负三十三) 难度级别:E: 运行时间限制:7000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行N次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar所有数的值设为v. 输入 第一行为一个正整数N.第二行为N个整数Ai.接下来N行每行4个正整数t,l,r,v.若t=2表

COJ WZJ的数据结构(负十八)splay_tree的天堂

WZJ的数据结构(负十八) 难度级别:E: 运行时间限制:100000ms: 运行空间限制:700KB: 代码长度限制:2000000B 试题描述 对于前一段样例: 输入 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格.为了考察垃圾回收的使用,我们精心准备了多组数据... 输出 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

COJ 0979 WZJ的数据结构(负二十一)

WZJ的数据结构(负二十一) 难度级别:C: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你实现一个数据结构,完成这样的功能: 给你一个N个点的图,初始状态无边. 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成树,输出“Not Yet”,否则输出当前最小生成树的权值. 输入 第一行两个正整数N,M.表示有N个点M个操作.接下来M行每行三个正整数u,v,w. 输出 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成

COJ 0995 WZJ的数据结构(负五)区间操作

WZJ的数据结构(负五) 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行M次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar中每个数的值+v. 输入 第一行为一个正整数N.第二行为N个整数Ai.第三行为一个正整数M.接下来M行每行4个正整数t,l,

COJ969 WZJ的数据结构(负三十一)

WZJ的数据结构(负三十一) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 A国有两个主基站,供给全国的资源.定义一个主基站能覆盖的范围为:以该主基站为圆心,半径为r的圆(包括边界).如果一个子基站能被一个主基站覆盖,则它是激活的.有N个事件,事件分两种:1.新建一个坐标位于(x,y)的子基站. 2.给出两个主基站的半径:r1.r2.询问处于非激活状态的子基站个数. 输入 第一行是四个正整数:x1.y1.x2.y2.表示

COJ966 WZJ的数据结构(负三十四)

WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u r"的Q个询问, 回答以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少.如果有多个节点,返回编号最小的. 输入 共有一组测试数据.第一行包含一个整数 n (1 ≤ n ≤ 10^5),表示节点总数.接下来的一行,包含 n 个数字,表示每个节点的权值 vi (1 ≤ vi ≤ 1

COJ968 WZJ的数据结构(负三十二)

WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变灭,灭变亮. 2 x k:询问当前所有亮灯的节点中距离x第k小的距离(注意如果x亮着也算入). 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi

COJ970 WZJ的数据结构(负三十)

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后