BZOJ 4262 线段树+期望

思路:

把询问离线下来,查询max和查询min相似,现在只考虑查询max

令sum[l,r,x]表示l到r内的数为左端点,x为右端点的区间询问的答案

那么询问就是sun[l1,r1,r2]-sum[l1,r1,l1-1]

从1到n枚举x,维护区间线段树表示sum[l,r,x],发现从x-1转移到x的过程中,每个数加上了max(a[pos]..a[x])的答案。

用单调队列维护一个单调递减的序列,由于a数列是随机的,这个队列期望有log个元素,所以只需要对这log段暴力修改,复杂度nlog^2n

或者,只在元素进队和出队的时候做一些操作,写起来会复杂很多,但复杂度nlogn

From heheda

(其实先把所有的数求出来 做一遍    再取相反数 做一遍就好啦)

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int N=200050,mod=1000000000;
struct Node{
    int id,l,r,pos,f;Node(){}
    Node(int I,int L,int R,int P,int F){id=I,l=L,r=R,pos=P,f=F;}
}node[N];
bool cmp(Node a,Node b){if(a.pos!=b.pos)return a.pos<b.pos;return a.f<b.f;}
int n,t,l1,r1,l2,r2,stk[N],top,tree[N*16],lazy[N*16],ans[N],a[N],maxx;
void insert(int l,int r,int pos,int L,int R,int wei){
    if(l>=L&&r<=R){lazy[pos]+=wei;tree[pos]+=(r-l+1)*wei;return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)insert(mid+1,r,rson,L,R,wei);
    else if(mid>=R)insert(l,mid,lson,L,R,wei);
    else insert(l,mid,lson,L,R,wei),insert(mid+1,r,rson,L,R,wei);
    tree[pos]=tree[lson]+tree[rson];
}
void push_down(int pos,int num){
    int lson=pos<<1,rson=pos<<1|1;
    lazy[lson]+=lazy[pos],lazy[rson]+=lazy[pos];
    tree[lson]+=lazy[pos]*(num-num/2),tree[rson]+=lazy[pos]*(num>>1);
    lazy[pos]=0;
}
int query(int l,int r,int pos,int L,int R){
    if(l>=L&&r<=R)return tree[pos];
    if(lazy[pos])push_down(pos,r-l+1);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)return query(mid+1,r,rson,L,R);
    else if(mid>=R)return query(l,mid,lson,L,R);
    else return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R);
}
void solve(){
    int now=1;
    for(int i=1;i<=maxx;i++){
        while(node[now].pos==i&&node[now].f==-1)ans[node[now].id]-=query(1,maxx,1,node[now].l,node[now].r),now++;
        while(top&&a[stk[top]]<=a[i])top--;
        stk[++top]=i;
        for(int j=1;j<=top;j++)insert(1,maxx,1,stk[j-1]+1,stk[j],a[stk[j]]);
        while(node[now].pos==i)ans[node[now].id]+=query(1,maxx,1,node[now].l,node[now].r),now++;
    }
}
signed main(){
    int fst=1023,sec=1025;
    for(int i=1;i<=100000;i++)
        a[i]=fst^sec,fst=fst*1023%mod,sec=sec*1025%mod;
    scanf("%lld",&t);
    for(int i=1;i<=t;i++){
        scanf("%lld%lld%lld%lld",&l1,&r1,&l2,&r2);
        node[++n]=Node(i,l1,r1,l2,-1);
        node[++n]=Node(i,l1,r1,r2,1);
        maxx=max(r1,max(maxx,r2));
    }
    sort(node+1,node+1+n,cmp);
    solve();
    memset(tree,0,sizeof(tree)),memset(lazy,0,sizeof(lazy));
    for(int i=1;i<=100000;i++)a[i]=-a[i];
    solve();
    for(int i=1;i<=t;i++)printf("%lld\n",ans[i]);
}
时间: 2024-09-15 13:21:19

BZOJ 4262 线段树+期望的相关文章

BZOJ 2752: [HAOI2012]高速公路(road) [线段树 期望]

2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1219  Solved: 446[Submit][Status][Discuss] Description Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站.Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1

JZYZOJ1527 [haoi2012]高速公路 线段树 期望

http://172.20.6.3/Problem_Show.asp?id=1527 日常线段树的pushdown写挂,果然每次写都想得不全面,以后要注意啊--求期望部分也不熟练,和平均数搞混也是orz,我已经是个期望都求不出来的废人了.这道题显然(大概)每个段的贡献是val[i]*(y-i+1)*(i-x+1);整体来说算是一看就是线段树的题. 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring>

[CF895E] Eyes Closed(线段树,期望)

Desctiption 传送门:Portal 大致题意: 给你一个序列, 支持两种操作: 1 l1 r1 l2 y2 在\([l1, r1]\)随机选择一个数a, \([l2, r2]\) 内随机选择一个数b, 交换a, b. 2 l r 询问一个区间的期望. \[ n \leq 200000; a_i \leq 1e9 \] Solution 根据==期望线性性==,只需要维护出==每个位置元素值的期望==就可以. ==区间操作期望==问题的经典套路是==维护出每个位置的期望==. 考虑一个数

bzoj 1018 线段树维护连通性

本题将一道LCT的题特殊化(支持加边和删边,询问图的连通性),将图变成了2×m的网格图,然后就神奇地可以用线段树来维护. 对于每个区间[l,r],维护其四个角落之间的连通性(仅仅通过[l,r]这段的边构建起的连通性). 查询[l,r]时,先计算出[1,l-1],[l,r],[r+1,c]这三个线段的连通性,然后将[l,r]的四个角变成并查集的4个点,先用[l,r]中的6种关系更新,在看是否可以从左上角的点通过左边区间绕道左下角,以及从右上角通过右边区间绕道右下角,该并的并起来后直接看查询的点是否

BZOJ 3681 线段树合并+网络流

思路: 暴力建图有n*m条边 考虑怎么优化 (那就只能加个线段树了呗) 然后我就不会写了..... 抄了一波题解 //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=10050,M=N*100,inf=0x3f3f3f3f; vector<int>vec[N]; int n,m,first[M],next[M],v[M],w[M],tot,cnt=2,S=1,T=2; int lson[M

BZOJ 1012 线段树或单调队列

1012: [JSOI2008]最大数maxnumber 题意:两种操作:1.查询当前数列中末尾L个数中的最大的数:2.当前数列末尾插入一个数. tags:水题 线段树 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i

BZOJ 4756 线段树合并(线段树)

思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100050; int n,col[N],cpy[N],tree[N*100],lso

BZOJ 1018 线段树维护图的连通性问题

思路: 我们可以搞一棵线段树 对于一段区间有6种情况需要讨论 左上右下.左上右上.左下右下.左下右上 这四种比较好维护 用左上右下举个例子吧 就是左儿子的左上右下&左区间到右区间下面有路&右儿子的左下右下 或者是左儿子的左上右上&左区间到右区间上面有路&右儿子的左上右下 还有两种  区间的左(右)端点上下能不能联通 需要维护 这种就是左儿子的上下连通或(左上右上&左上右下&左到右两条路都联通&右儿子的上下联通) (假设c1<c2) 最后要查的是

bzoj 3211 线段树

开方操作最多进行5次就可以把出现的任何数变成1. 所以用线段树暴力修改,以后修改时只需看一下是否当前区间都是0或1,如果是那么就直接返回. 1 /************************************************************** 2 Problem: 3211 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1976 ms 7 Memory:7068 kb 8 **************