Acdream 1738 世风日下的哗啦啦族I 树套树

世风日下的哗啦啦族I

Time Limit: 20 Sec  Memory Limit: 256 MB

题目连接

http://acdream.info/problem?pid=1738

Description

"世风日下啊,女生不穿裙子的太少了"
"这不是社会的进步吗(逃"
"哎,是否可以建立一种结构统计一下各学院各专业各班级女生穿裙子的数量以及裙子的长度"
"然后查询区间裙子最短值?"
"并输出这个区间 穿这个裙子长度的妹子 有多少个?"
"然后判断下在有风的情况下,多少妹子是安全的."

"maya 哗啦啦族真是太可怕啦!"

Input

第一行 n,m表示n个妹子,m个操作
第二行 a1 a2 a3 …… an,n个整数,表示妹子一开始的裙子长度,如果穿的是裤子,ai=-1
下面m行:
总共3种操作
1 a b
修改a妹子的裙子,变成b长度
2 l r
查询[l,r]区间的妹子最短的裙子长度,并输出有多少个妹子穿这个长度裙子的
3 l r t
输出[l,r]区间的妹子身穿裙子长度小于等于t的个数
1<=n,m<=50000
1<=a<=n
1<=b<=50000
1<=ai<=50000
1<=l<=r<=n
0<=t<=50000

Output

根据询问,输出答案

具体看样例

Sample Input

3 3
1 2 3
1 1 4
2 1 3
3 1 3 2

Sample Output

2 1
1

HINT

题意

题解:

啊,线段树套平衡树

好麻烦……

http://pan.baidu.com/s/1hqu4qBa

代码:

//qscqesze
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
typedef long long ll;
using namespace std;
//freopen("D.in","r",stdin);
//freopen("D.out","w",stdout);
#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
#define maxn 200001
#define mod 10007
#define eps 1e-9
int Num;
char CH[20];
//const int inf=0x7fffffff;   //нчоч╢С
const int inf=0x3f3f3f3f;
/*

inline void P(int x)
{
    Num=0;if(!x){putchar(‘0‘);puts("");return;}
    while(x>0)CH[++Num]=x%10,x/=10;
    while(Num)putchar(CH[Num--]+48);
    puts("");
}
*/
inline ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
inline void P(int x)
{
    Num=0;if(!x){putchar(‘0‘);puts("");return;}
    while(x>0)CH[++Num]=x%10,x/=10;
    while(Num)putchar(CH[Num--]+48);
    puts("");
}
//**************************************************************************************

#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
const int MAXN=5e4+100;

struct SplayTree {
    int sz[MAXN*20];
    int ch[MAXN*20][2];
    int pre[MAXN*20];
    int top;
    int rt[MAXN<<2];
    inline void up(int x){
        sz[x]  = cnt[x]  + sz[ ch[x][0] ] + sz[ ch[x][1] ];
    }
    inline void Rotate(int x,int f){
        int y=pre[x];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);
    }
    inline void Splay(int x,int goal,int root){//将x旋转到goal的下面
        while(pre[x] != goal){
            if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
            else   {
                int y=pre[x],z=pre[y];
                int f = (ch[z][0]==y);
                if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt[root]=x;
    }
    inline void RTO(int k,int goal,int root){//将第k位数旋转到goal的下面
        int x=rt[root];
        while(sz[ ch[x][0] ] != k-1) {
            if(k < sz[ ch[x][0] ]+1) x=ch[x][0];
            else {
                k-=(sz[ ch[x][0] ]+1);
                x = ch[x][1];
            }
        }
        Splay(x,goal,root);
    }
    inline void vist(int x){
        if(x){
            printf("结点%2d : 左儿子  %2d   右儿子  %2d   %2d sz=%d\n",x,ch[x][0],ch[x][1],val[x],sz[x]);
            vist(ch[x][0]);
            vist(ch[x][1]);
        }
    }
    inline void Newnode(int &x,int c){
        x=++top;
        ch[x][0] = ch[x][1] = pre[x] = 0;
        sz[x]=1; cnt[x]=1;
        val[x] = c;
    }
    inline void init(){
        top=0;
    }
    inline void Insert(int &x,int key,int f,int root){
        if(!x) {
            Newnode(x,key);
            pre[x]=f;
            Splay(x,0,root);
            return ;
        }
        if(key==val[x]){
            cnt[x]++;
            sz[x]++;
            return ;
        }else if(key<val[x]) {
            Insert(ch[x][0],key,x,root);
        } else {
            Insert(ch[x][1],key,x,root);
        }
        up(x);
    }

    void Del(int root){  //删除根结点
         if(cnt[rt[root]]>1)
         {
            cnt[rt[root]]--;
         }
         else
         {
             int t=rt[root];
             if(ch[rt[root]][1]) {
                 rt[root]=ch[rt[root]][1];
                 RTO(1,0,root);
                 ch[rt[root]][0]=ch[t][0];
                 if(ch[rt[root]][0]) pre[ch[rt[root]][0]]=rt[root];
             }
             else rt[root]=ch[rt[root]][0];
             pre[rt[root]]=0;
         }
         up(rt[root]);
    }
    void findpre(int x,int key,int &ans){  //找key前趋
        if(!x)  return ;
        if(val[x] <= key){
            ans=x;
            findpre(ch[x][1],key,ans);
        } else
            findpre(ch[x][0],key,ans);
    }
    void findsucc(int x,int key,int &ans){  //找key后继
        if(!x) return ;
        if(val[x]>=key) {
            ans=x;
            findsucc(ch[x][0],key,ans);
        } else
            findsucc(ch[x][1],key,ans);
    }
    void findkey(int x,int key,int &ans)//找key
    {
        if(!x)return;
        if(val[x]==key)
            ans=x;
        else if(val[x]>key)
            findkey(ch[x][0],key,ans);
        else
            findkey(ch[x][1],key,ans);
    }
    //找第K大数
    inline int find_kth(int x,int k,int root){
        if(k<sz[ch[x][0]]+1) {
            return find_kth(ch[x][0],k,root);
        }else if(k > sz[ ch[x][0] ] + cnt[x] )
            return find_kth(ch[x][1],k-sz[ch[x][0]]-cnt[x],root);
        else{
            Splay(x,0,root);
            return val[x];
        }
    }
    int cnt[MAXN*20];
    int val[MAXN*20];
//---------------------------------------------
//建立线段树和线段树中的每个结点的平衡树
    struct node
    {
        int l,r,x;
    }mi[MAXN*2];
    void build(int l,int r,int root)
    {
        mi[root].x=99999999;
        mi[root].l=l,mi[root].r=r;
        rt[root]=0;
        for(int i=l;i<=r;i++)
            Insert(rt[root],a[i],0,root);
        if(l>=r)
        {
            mi[root].x=a[r];
            return;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        mi[root].x=min(mi[root<<1].x,mi[root<<1|1].x);
    }
    void updatemi(int x,int l,int k)
    {
        int L=mi[x].l,R=mi[x].r;
        if(L==R)
        {
            mi[x].x=k;
            return;
        }
        int mid=(L+R)>>1;
        if(l<=mid)
            updatemi(x<<1,l,k);
        else
            updatemi(x<<1|1,l,k);
        mi[x].x=min(mi[x<<1].x,mi[x<<1|1].x);
    }
    int querymi(int x,int l,int r)
    {
        int L=mi[x].l,R=mi[x].r;
        if(l<=L&&R<=r)
            return mi[x].x;
        int mid=(L+R)>>1;
        if(r<=mid)
            return querymi(x<<1,l,r);
        else if(l>mid)
            return querymi(x<<1|1,l,r);
        else
            return min(querymi(x<<1,l,r),querymi(x<<1|1,l,r));
    }
    void update(int l,int r,int root,int i,int x)
    {
        int ans=0;
        findkey(rt[root],a[i],ans);
        Splay(ans,0,root);
        Del(root);
        Insert(rt[root],x,0,root);

        if(l>=r)return;
        int m=(l+r)>>1;
        if(i<=m)update(lson,i,x);
        else update(rson,i,x);
    }
    int cntLess(int x,int key)
    {
        int ret=0;
        while(x)
        {
            if(val[x]>key)
                x=ch[x][0];
            else
            {
                ret+=cnt[x]+sz[ch[x][0]];
                x=ch[x][1];
            }
        }
        return ret;
    }
    int getnumLess(int l,int r,int root,int L,int R,int x)
    {
        if(L<=l&&R>=r)
            return cntLess(rt[root],x);
        int m=(l+r)>>1;
        int ret=0;
        if(L<=m)ret+=getnumLess(lson,L,R,x);
        if(R>m)ret+=getnumLess(rson,L,R,x);
        return ret;
    }
    int search(int L,int R,int k)
    {
        int l=0,r=INF;
        int ans=0;
        return getnumLess(1,n,1,L,R,k);
    }
    void solve()
    {
        scanf("%d%d",&n,&m);
        REP(i,1,n)
            scanf("%d",&a[i]);
        build(1,n,1);
        REP(i,1,m)
        {
            int x,y,z;
            char str[4];
            scanf("%s",str);
            if(str[0]==‘1‘)
            {
                scanf("%d%d",&x,&y);
                updatemi(1,x,y);
                update(1,n,1,x,y);
                a[x]=y;
            }
            else if(str[0]==‘2‘)
            {
                scanf("%d%d",&x,&y);
                int k=querymi(1,x,y);
                int kk=search(x,y,k)-search(x,y,k-1);
                printf("%d %d\n",k,kk);
            }
            else
            {
                scanf("%d%d%d",&x,&y,&z);
                int k=search(x,y,z);
                printf("%d\n",k);
            }
        }
    }
    int a[MAXN];
    int n,m;

}spt;
int main()
{
    spt.init();
    spt.solve();
    return 0;
}
时间: 2024-10-14 22:04:57

Acdream 1738 世风日下的哗啦啦族I 树套树的相关文章

acdream 1738 世风日下的哗啦啦族I 分块

世风日下的哗啦啦族I Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acdream.info/problem?pid=1738 Description "世风日下啊,女生不穿裙子的太少了" "这不是社会的进步吗(逃" "哎,是否可以建立一种结构统计一下各学院各专业各班级女生穿裙子的数量以及裙子的长度" "然后查询区间裙子最短值?" "并输出这个区间 穿这个裙

acdream 1738 世风日下的哗啦啦族I

原题链接:http://acdream.info/problem?pid=1738 树套树裸题,如下: 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #define lc root<<1 7 #define rc root<<1|1 8 using std::so

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

HDU HDOJ5412(树套树

题目:要求支持带修改维护区间第k大的值.所谓的动态区间第k大. 思路:题解说的是树状数组套treap,然而没想通树状数组怎么维护...线段树的话就是把所有的值离散化一下,离线建个关于值的线段树,每个节点是一个treap,treap里的值用位置做关键字,然后做区间查询,复杂度是O(nlogn*logn).基本也是经典的树套树做法....然后赛后写了两遍都没过.....今天心血来潮再挑战一下,结果从8点调到晚上1点.其间各种爆内存各种re各种t.....随机数据对拍了好久没拍出问题来....然后一直

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def