zoukankan      html  css  js  c++  java
  • [vijos 1448]: 校门外的树(树状数组/线段树) 标签: vijos 2017-05-23 16:36 62人阅读 评论(0)

    描述

    校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
    如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
    K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
    K=2,读入l,r表示询问l~r之间能见到多少种树
    (l,r>0)
    格式

    输入格式

    第一行n,m表示道路总长为n,共有m个操作
    接下来m行为m个操作
    输出格式

    对于每个k=2输出一个答案

    样例1

    样例输入1

    5 4
    1 1 3
    2 2 5
    1 2 4
    2 3 5
    样例输出1
    1
    2

    限制

    1s

    提示

    范围:20%的数据保证,n,m<=100
    60%的数据保证,n <=1000,m<=50000
    100%的数据保证,n,m<=50000

    来源

    dejiyu@CSC WorkGroup

    把树理解为左右括号内的区间 用左右括号
    因为要不断的更改单点和区间计算
    使用两个树状数组 一个记录左 一个记录右

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int l[50010],r[50010];
    int n,m;
    int lowbit(int x){
        return x&(-x);
    }
    void add(int x,int c[]){
        while(x<=n){
            c[x]++;
            x+=lowbit(x);
        }
    }
    int getsum(int x,int c[]){
        int sum=0;
        while(x>0){
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int k,x,y;
            scanf("%d%d%d",&k,&x,&y);
            if(k==1){
                add(x,l);
                add(y,r);
            }
            else
            {
                cout<<getsum(y,l)<<endl;
                cout<<getsum(x-1,r)<<endl;
                cout<<getsum(y,l)-getsum(x-1,r)<<endl;
                //从开始到y的左括号的数量减去 x左边右括号的数量
            }
        }
        return 0;
    }
    

    线段树做法
    和树状数组一样

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int w[200010];//内存4倍!!!! 
    struct node{
        int left;
        int right;
        int sum[2];//0是左括号 
        int addv[2];//1 右 
    }a[200010];
    void pushdown(int p,int op){
        if(a[p].addv[op]!=0) 
        {
            a[2*p].addv[op]+=a[p].addv[op];
            a[2*p].sum[op]+=a[p].addv[op]*(a[2*p].right-a[2*p].left+1);
            a[2*p+1].addv[op]+=a[p].addv[op];
            a[2*p+1].sum[op]+=a[p].addv[op]*(a[2*p+1].right-a[2*p+1].left+1);
            a[p].addv[op]=0;
        }
    }
    void build(int l,int r,int p){
        a[p].left=l;
        a[p].right=r;
        if(l==r) return;
        if(l<r){
            build(l,(l+r)/2,2*p);
            build((l+r)/2+1,r,2*p+1);
        }
    }
    int query(int l,int r,int p,int op){
        if(l>r) return 0;
        if(a[p].left==l&&a[p].right==r) return a[p].sum[op];
        pushdown(p,op); 
        int mid=(a[p].left+a[p].right)/2;
        if(r<=mid)  return query(l,r,2*p,op);   
        else if(l>mid) return query(l,r,2*p+1,op);  
        else return query(l,mid,2*p,op)+query(mid+1,r,2*p+1,op);
    }
    void update(int x,int p,int op){
        if(a[p].left==x&&a[p].right==x){
            a[p].sum[op]++;a[p].addv[op]++;return;
        }
        int mid=(a[p].left+a[p].right)/2;
        pushdown(p,op);
        if(x<=mid)  update(x,2*p,op);
        else if(x>mid) update(x,2*p+1,op);
        a[p].sum[op]=a[2*p].sum[op]+a[2*p+1].sum[op];
    }
    int main(){
        int n,m;    
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--){
            int k,x,y;
            scanf("%d%d%d",&k,&x,&y);
            if(k==1){
                update(x,1,0);
                update(y,1,1);
            }
            else {
                printf("%d
    ",query(1,y,1,0)-query(1,x-1,1,1));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    CSP2020 T1儒略日 暴力模拟90pts代码
    CSP-S 2019 D1T2括号树
    P3593 [POI2015]TAB
    P5145 漂浮的鸭子
    CH0503 奇数码问题
    [NOIP2012]国王游戏 -高精度-贪心-
    费解的开关
    P1040 加分二叉树
    初步学习线段树
    P2758 编辑距离 简单DP
  • 原文地址:https://www.cnblogs.com/xljxlj/p/7183648.html
Copyright © 2011-2022 走看看