zoj 3573 Under Attack(线段树 标记法 最大覆盖数)

Under Attack

Time Limit:  10 Seconds      Memory Limit:  65536 KB

Doctor serves at a military air force base. One day, the enemy launch a sudden attack and the base is under heavy fire. The fighters in the airport must take off to intercept enemy bombers. However, the enemies know this clearly and they now focus on destroying
the runway. The situation is becoming worse rapidly!

Every part of the runway has a damage level. On each bombing run, the damage level is increased by the bomb‘s damage . Fortunately, the enemy bombers has to stop bombing the runway when they run out of ammo. Then the ground crew have time to evaluate the situation
of runway so that they can come to repair the runway ASAP after enemy attacks. The most heavily-damaged part on fighters‘ taking off and landing path should first be repaired. Assume that runway start from north and head to south , and fighters will take off
or land only from north to south or vice versa.

Now that the task is clear, the ground crew need the cooridinates of two points: first that is the most damaged point from north to south, second is the most damaged point from south to north.The base‘s central mainframe is down under hacker attack. So Doctor
could only use his poor little and shabby notebook to fulfill this task. Can you help him?

Input

The input consists of multiple cases.

The first line is the runway length L. L can be up to 15000.

Next lines will describe enemy bombing runs ,each line describes effect range start end of each bombing run and enemy bomb damage d.if start is -1, this case ends..

There can be up to 3000 bombing run, each time the damage is up to 100.

Notice that the bombing range is from north to south, and runway range is [0,len].

Output

Output the cooridinates of two points: first that is the most damaged point from north to south, second is the most damaged point from south to north.

Sample Input

10

1 5 2

6 9 2

-1 -1 -1

Sample Output

1 9

从早上起 这都一上午了,这个大水题终于a了!在不知道 最大覆盖次数求法之前,我先求出全长线段中最大值,也就是普通的区间更新加延迟标记,然后利用calculate函数从两边分别开始遍历找到左右最大值的位置,从多组测试数据上来看 ,并没有什么差错,但就是wrong,后学会最大覆盖次数,1a。

见到的请帮我看看到底是哪些 数据错了!!!!!!

第二段代码是正确地;

wrong code:

#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
const int INF=15003;
struct Tree
{
    int left;
    int right;
    int mark;
    int Max;
} tree[INF<<2];

int create(int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    if(left==right)
    {
        return tree[root].Max=0;
    }
    int a,b,middle=(left+right)>>1;
    a=create(root<<1,left,middle);
    b=create(root<<1|1,middle+1,right);
    return tree[root].Max=max(a,b);
}

void update_mark(int root)
{
    if(tree[root].mark)
    {
        tree[root].Max+=tree[root].mark;
        if(tree[root].left!=tree[root].right)
        {
            tree[root<<1].mark+=tree[root].mark;
            tree[root<<1|1].mark+=tree[root].mark;
        }
        tree[root].mark=0;
    }
}

int calculate(int root,int left ,int right)
{
    update_mark(root);
    if(tree[root].left>right||tree[root].right<left)
        return 0;
    if(tree[root].left>=left&&tree[root].right<=right)
    {
        return tree[root].Max;
    }
    int a,b;
    a=calculate(root<<1,left,right);
    b=calculate(root<<1|1,left,right);
    return max(a,b);
}

int   update(int root,int left,int right,int val)
{
    update_mark(root);
    if(tree[root].left>right||tree[root].right<left)
        return tree[root].Max;
    if(tree[root].left>=left&&tree[root].right<=right)
    {
        tree[root].mark+=val;
        update_mark(root);
        return tree[root].Max;
    }
    int a=update(root<<1,left,right,val);
    int b=update(root<<1|1,left,right,val);
    return tree[root].Max=max(a,b);

}

int main()
{
    int L;
    while(scanf("%d",&L)!=EOF)
    {
        create(1,0,L);
        int x,y,z;
        while(scanf("%d%d%d",&x,&y,&z)!=EOF)
        {
            if(x>y)
                swap(x,y);
            if(x!=-1)
            {
                update(1,x,y,z);
            }
            else break;
        }
        int k=calculate(1,0,L);
        int locl,locr;
        for(int i=0; i<=L;i++)
        {
            if(calculate(1,i,i)==k)
            {

                locl=i;
                break;
            }
        }
        for(int i=L;i>=0;i--)
        {
            if(calculate(1,i,i)==k)
            {
                locr=i;
                break;
            }
        }
        printf("%d,%d\n",locl,locr);
    }
    return 0;
}
/*
10
1 2  3
0 0 3
5 8 4
0 0 3
2 2 2
-1 1 3
*/
</pre><pre name="code" class="cpp">正确 代码:
<pre name="code" class="cpp">#include<stdio.h>
struct Tree
{
    int left,right,cover;
} tree[15000<<2];
int covered=0;
void create(int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    tree[root].cover=0;
    if(right==left)
        return ;
    int mid=(left+right)>>1;
    create(root<<1,left,mid);
    create(root<<1|1,mid+1,right);
}

void update(int root,int left,int right,int val)
{
    if(left<=tree[root].left&&tree[root].right<=right)
    {
        tree[root].cover+=val;
        return ;
    }
    int m=(tree[root].left+tree[root].right)>>1;
    if(m>=left)update(root<<1,left,right,val);
    if(m<right)update(root<<1|1,left,right,val);
}

void  calculate(int root,int x)
{
    covered+=tree[root].cover;
    if(tree[root].left==tree[root].right)
        return ;
    int m=(tree[root].left+tree[root].right)>>1;
    if(m>=x)
        calculate(root<<1,x);
    else
        calculate(root<<1|1,x);

}

int main()
{
    int L;
    while(scanf("%d",&L)!=EOF)
    {
        create(1,0,L);
        int x,y,z;
        while(scanf("%d%d%d",&x,&y,&z))
        {
            if(x==-1)
                break;
            update(1,x,y,z);
        }
        int loc1, loc2,Max=0;
        for(int i=0; i<=L; i++)
        {
            covered=0;
            calculate(1,i);
            if(covered>Max)
            {
                Max=covered;
                loc1=i;
            }
        }
        for(int i=L,Max=0; i>=0; i--)
        {
            covered=0;
            calculate(1,i);
            if(covered>Max)
            {
                Max=covered;
                loc2=i;
            }
        }
        printf("%d %d\n",loc1,loc2);
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 02:08:46

zoj 3573 Under Attack(线段树 标记法 最大覆盖数)的相关文章

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

POJ 2155 Matrix 二维线段树+标记永久化?

题意:链接 方法:二维线段树+标记永久化 解析:题意是比较明朗的,算一下内存发现4000^2也是可以接受的,于是就开始yy二维线段树? 对于第一层x的线段树,每个节点开一整棵y线段树. 用个二维数组就实现了? 不过发现个问题啊,这题怎么pushdown啊,标记传不下去啊.如果给x打个标记那么怎么知道y传那段啊? 于是就学了新的东西?标记永久化. 本题是单点查询嘛,标记永久化就应该是把相应的区间直接异或,不用往下传?那查询的时候怎么办呢?只需要在查询的时候把所有路过该点的区间都异或起来就OK了.貌

[知识点]线段树标记永久化

前言: 本文由Hallmeow原创,转载请注明出处! 由于打丧心病狂的 [BZOJ 4826]影魔  导致需要学习标记永久化,于是入坑OvO 知识点:线段树标记永久化 对于树套树,主席树等使用到线段树的比较复杂的数据结构,如果我们区间修改的话,打标记后pushdown或者pushup是很费劲的 那么我们能不能不用pushdown和pushup呢?当然可以啦!这样就用到标记永久化了! 原理就是: 在路过该节点的时候把修改对答案的影响加上,来省去标记下放的过程 实现起来: 线段树的每个节点维护 su

线段树标记永久化

前言 对于树套树,主席树等使用到线段树的比较复杂的数据结构,如果区间修改的话,打标记后pushdown或者pushup是很难做到的完全不行吧 所以这个时候,一个神奇的东西诞生了... 正题 线段树标记永久化,维护一个标记,假设为cov,再维护一个sum 假设修改区间[ql, qr]全部加上v: 和平常一样,到这个区间后cov[x] += v 但是我们又不想pushup,怎么办? 很好做,更新的时候每次sum[x] += v * (qr - ql + 1) (注意这里的qr,ql是完全被包含于线段

ZOJ 5332 Calculation(离线 + 线段树)

题目链接 :http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5332 比赛的时候没有做出来,赛后看了官方题解,虽然各种orz但是依旧只能orz(标程写得真是犀利),然后可耻的到网上找了下题解... 做法是线段树 + 离线搞, 网上那种对于[l, r]中的l从大到小排序很精妙(有一篇竟然说是以r为关键字,,,然后代码里面却是l...汗), 再注意到gcd()对于每一个起点来说,是单调递减的,这样可以乱搞了... 如果还不是很明白

zoj 3511 Cake Robbery(线段树)

题目链接:zoj 3511 Cake Robbery 题目大意:就是有一个N边形的蛋糕,切M刀,从中挑选一块边数最多的,保证没有两条边重叠. 解题思路:有多少个顶点即为有多少条边,所以直接按照切刀切掉点的个数排序,然后用线段树维护剩下的还有哪些点. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int

Vijos1448题解---线段树+括号法

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: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输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5

zoj 3813 Alternating Sum(线段树)

题目链接:zoj 3813 Alternating Sum 题目大意:给定一个P,S是以P为循环的无限串,定义G(i,j),现在有两种操作: 1 x d:将P中x的位置变为d 2 l r:查询S中l-r之间所有的G(i, j)的和 解题思路:线段树的区间查询点修改. 根据G(i,j)的公式可以推导出:每次查询l~r这段区间的答案为: 奇数:sl?len+sl+2?(len?2)+sl+4?(len?4)+?+sr?1 偶数:sl?len+sl+2?(len?2)+sl+4?(len?4)+?+s