cogs——1008. 贪婪大陆(清华巨佬代码)——树状数组

1008. 贪婪大陆

★★   输入文件:greedisland.in   输出文件:greedisland.out   简单对比
时间限制:1 s   内存限制:128 MB

试题四:贪婪大陆 
【题目描述】 
面对蚂蚁们的疯狂进攻,小FF的Tower defense宣告失败……人类被蚂蚁们逼到了Greed Island上的一个海湾。现在,小FF的后方是一望无际的大海,前方是变异了的超级蚂蚁。 小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻。 
小FF最后一道防线是一条长度为N的战壕, 小FF拥有无数多种地雷,而SCV每次可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷。 由于情况已经十万火急,小FF在某些时候可能会询问你在[ L‘ , R‘] 区间内有多少种不同的地雷, 他希望你能尽快的给予答复。 
【输入格式】 
第一行为两个整数n和m; n表示防线长度, m表示SCV布雷次数及小FF询问的次数总和。 
接下来有m行, 每行三个整数Q,L , R; 若Q=1 则表示SCV在[ L , R ]这段区间布上一种地雷, 若Q=2则表示小FF询问当前[ L , R ]区间总共有多少种地雷。 
【输出格式】 
对于小FF的每次询问,输出一个答案(单独一行),表示当前区间地雷总数。 
【输入样例】 
5 4 
1 1 3 
2 2 5 
1 2 4 
2 3 5 
【输出样例】 
【数据范围】 
对于30%的数据: 0<=n, m<=1000; 
对于100%的数据: 0<=n, m<=10^5.
代码:
one
#include<cstdio>

const int MAXN(100010);

int n,m,tot;
int t[MAXN<<2][2];

void insert(int x,int k,int left=1,int right=n,int p=1){
    if(left==right){
        t[p][k]++;
        return;
    }
    int mid=(left+right)>>1;
    if(x<=mid)insert(x,k,left,mid,p<<1);
    else insert(x,k,mid+1,right,p<<1|1);
    t[p][0]=t[p<<1][0]+t[p<<1|1][0];
    t[p][1]=t[p<<1][1]+t[p<<1|1][1];
}
int query(int x,int y,int k,int left=1,int right=n,int p=1){
    if(x<=left&&right<=y)
        return t[p][k];
    int mid=(left+right)>>1,ans=0;
    if(x<=mid)ans=ans+query(x,y,k,left,mid,p<<1);
    if(y>mid)ans=ans+query(x,y,k,mid+1,right,p<<1|1);
    return ans;
}

int main(){
    freopen("greedisland.in","r",stdin);
    freopen("greedisland.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int q=1;q<=m;q++){
        int ty,x,y;
        scanf("%d%d%d",&ty,&x,&y);
        if(ty==1){
            insert(x,0);
            insert(y,1);
            tot++;
        }
        else
            printf("%d\n",tot-query(1,x-1,1)-query(y+1,n,0));
    }
    return 0;
}

two

#include<cstdio>

const int MAXN(100010);

int n,m,tot;
int t[MAXN<<2],tag[MAXN<<2],mark[MAXN<<2];

void increase(int p,int k){
    t[p]+=k;
    tag[p]+=k;
    mark[p]+=k;
}

void push_down(int p){
    int& d=tag[p];
    increase(p<<1,d);
    increase(p<<1|1,d);
    d=0;
}

void insert(int x,int y,int left=1,int right=n,int p=1){
    if(x<=left&&right<=y){
        increase(p,1);
        return;
    }
    push_down(p);
    int mid=(left+right)>>1;
    if(x<=mid)insert(x,y,left,mid,p<<1);
    if(y>mid) insert(x,y,mid+1,right,p<<1|1);
    t[p]++;
    if(x<=mid&&y>mid)mark[p]++;
}
int query(int x,int y,int left=1,int right=n,int p=1){
    if(x<=left&&right<=y)
        return t[p];
    push_down(p);
    int mid=(left+right)>>1,ans=0;
    if(x<=mid)ans=ans+query(x,y,left,mid,p<<1);
    if(y>mid)ans=ans+query(x,y,mid+1,right,p<<1|1);
    if(x<=mid&&y>mid)ans-=mark[p];
    return ans;
}

int main(){
    freopen("greedisland.in","r",stdin);
    freopen("greedisland.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int q=1;q<=m;q++){
        int ty,x,y;
        scanf("%d%d%d",&ty,&x,&y);
        if(ty==1)
            insert(x,y);
        else
            printf("%d\n",query(x,y));
    }
    return 0;
}
时间: 2024-11-06 15:10:46

cogs——1008. 贪婪大陆(清华巨佬代码)——树状数组的相关文章

cogs 1008 贪婪大陆

/* 不要思维定视 盯着线段树维护l r 的ans不放 显然没法区间合并 换一种思路 如果打暴力的话 O(nm) 每次询问 扫一遍之前所有的修改 有交点则说明种数++ 接下来考虑如何优化 我们把每个区间看做(l,r)的坐标内的点 然后查询区间L<=li<=R L<=ri<=R内有多少点 这样的查询在二维坐标里不会查(反正我不会..)将坐标轴转化成两个一维的线段 这样我们就又面临一个问题 会有重复 那就用排除法 总数-不重复区间的 又因为保证了 r>=l 所以l轴的[r+1,n

COGS1008. 贪婪大陆[树状数组 模型转换]

1008. 贪婪大陆 ★★   输入文件:greedisland.in   输出文件:greedisland.out   简单对比时间限制:1 s   内存限制:128 MB 试题四:贪婪大陆  [题目描述]  面对蚂蚁们的疯狂进攻,小FF的Tower defense宣告失败……人类被蚂蚁们逼到了Greed Island上的一个海湾.现在,小FF的后方是一望无际的大海,前方是变异了的超级蚂蚁. 小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻. 

luoguP2184 贪婪大陆 题解(树状数组)

P2184 贪婪大陆  题目 其实很容易理解就是询问一段区间内有多少段不同的区间 然后再仔细思索一下会发现: 1.只要一个区间的开头在一个节点i的左边,那么这个区间包含在区间1~i中. 2.只要一个区间的尾部在一个节点j的左边,那么这个区间肯定不属于j之后的所有区间 这时候就不难想到用两个树状数组维护: 第一个:维护节点i之前有多少个区间的开头 第二个:维护节点j之前有多少个区间的结尾 不难证明拿sum[i]-sum[j]得到的就是i~j中间地雷的个数(手动模拟一波就一清二楚了) #includ

[luoguP2184] 贪婪大陆(树状数组)

传送门 用两个树状数组,cr 维护 1....x 中 r 的数量 cl 维护 1....x 中 l 的数量 求答案的时候只需要求 y 前面 被作为左端点 的个数 - x 前面 被作为右端点的个数 ——代码 1 #include <cstdio> 2 3 using namespace std; 4 5 const int MAXN = 1000001; 6 int n, m; 7 int cl[MAXN], cr[MAXN]; 8 9 inline void add1(int x) { for

代码与算法集锦-归并排序+树状数组+快排+深度优先搜索+01背包(动态规划)

归并排序 求逆序数 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 首先考虑下如何将将二个有序数列合并.这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数.然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可. //将有序数组a[]和b[]合并到c[]中 void MemeryArray(int a[], int n, int b[], int m, int c

[清华集训2017]小 Y 和地铁(神奇思路,搜索,剪枝,树状数组)

世界上最不缺的就是好题. 首先考虑暴搜.(还有什么题是从这东西推到正解的……) 首先单独一个换乘站明显没用,只用考虑一对对的换乘站. 那么有八种情况:(从题解偷图)         然后大力枚举每个换乘站的情况.同时判断交点.$O(n\times 8^{\frac{n}{2}})$. 然后考虑这种情况: 发现对于任意一条地铁线,要么与这两个都有交点,要么可以与这两个都没有交点.(其实会有与一个有两个交点,与另一个没有交点的情况.这时也可以把这条线换个方向,答案不会更差.思考思考为什么) 那么合法

贪婪大陆 树状数组

题目背景 面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败--人类被蚂蚁们逼到了Greed Island上的一个海湾.现在,小FF的后方是一望无际的大海, 前方是变异了的超级蚂蚁. 小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻. 题目描述 小FF最后一道防线是一条长度为N的战壕, 小FF拥有无数多种地雷,而SCV每次可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷. 由于情况已经十万火急,小FF在某些时候可能会询

[COGS 1535] [ZJOI2004]树的果实 树状数组+桶

我们用树状数组做差就可以解决一切问题,我用桶排并用此来表示出第几大就可以直接求前缀和了 #include<cstdio> #include<algorithm> #define MAXN 100010 using namespace std; inline int read() { int sum=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch&l

COGS 577 蝗灾 cdq分治+树状数组

题目链接:点击打开链接 cdq入门资料:点击打开链接 思路:首先根据上面的ppt可知cdq分治: solve(l, mid); 计算[l,mid] 对 [mid+1, r] 区间的影响 solve(mid+1, r); 计算影响部分,把询问拆成2个,对x排序后搞搞即可. #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <std