NYOJ 士兵杀敌系列

int 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;
}

加速外挂,因为只有输入功能,所以加速外挂可以在大量数据读入的时候有明显地加速效果

士兵杀敌(一)
时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述
南将军手下有N个士兵,分别编号1N,这些士兵的杀敌数都是已知的。

小工是南将军手下的军师,南将军现在想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。

注意,南将军可能会问很多次问题。

输入
只有一组测试数据
第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示南将军询问的次数(1<M<100000)
随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
随后的M行每行有两个整数m,n,表示南将军想知道第m号到第n号士兵的总杀敌数(1<=m,n<=N)。
输出
对于每一个询问,输出总杀敌数
每个输出占一行
样例输入
5 2
1 2 3 4 5
1 3
2 4
样例输出
6
9

最优代码直接O(n)草,不过毕竟是分类是数据结构嘛,就用数据结构来做啦。
裸线段树或者裸树状数组。区间求和。注意cin,cout会T掉。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define scini(n) scanf("%d", &n)
#define scinl(n) scanf("%lld", &n)
#define scinii(n, m) scanf("%d%d", &n, &m)
#define scinll(n, m) scanf("%lld%lld", &n, &m)
#define scout(n) printf("%d\n", n);

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 50010;
using namespace std;
int res[1000100];
int N;
int 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;
}
void update(int i, int add)
{
    while(i <= N){
        res[i] += add;
        i += lowbit(i);
    }
}
int query(int i)
{
    int ret = 0;
    while(i > 0){
        ret += res[i];
        i -= lowbit(i);
    }
    return ret;
}
int main()
{
    int M;
    N = read();
    M = read();
    int num;
    mes(res, 0);
    for(int i = 1; i <= N; ++i){
        num = read();
        update(i, num);
    }
    int a, b;
    while(M--){
        a = read();
        b = read();
        printf("%d\n", (query(b)-query(a-1)));
    }
    return 0;
}
士兵杀敌(二)
时间限制:1000 ms  |  内存限制:65535 KB
难度:5
描述
南将军手下有N个士兵,分别编号1N,这些士兵的杀敌数都是已知的。

小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。

南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。

输入
只有一组测试数据
第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)
随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100),表示第I个士兵新增杀敌数为A.
输出
对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行
样例输入
5 6
1 2 3 4 5
QUERY 1 3
ADD 1 2
QUERY 1 3
ADD 2 3
QUERY 1 2
QUERY 1 5
样例输出
6
8
8
20

BIT水过,多了判断,不过是裸BIT,单点跟新,区间求和。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define scini(n) scanf("%d", &n)
#define scinl(n) scanf("%lld", &n)
#define scinii(n, m) scanf("%d%d", &n, &m)
#define scinll(n, m) scanf("%lld%lld", &n, &m)
#define scout(n) printf("%d\n", n);

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 50010;
using namespace std;
int res[1000100];
int N;
int 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;
}
void update(int i, int add)
{
    while(i <= N){
        res[i] += add;
        i += lowbit(i);
    }
}
int query(int i)
{
    int ret = 0;
    while(i > 0){
        ret += res[i];
        i -= lowbit(i);
    }
    return ret;
}
int main()
{
    int M;
    N = read();
    M = read();
    int num;
    mes(res, 0);
    for(int i = 1; i <= N; ++i){
        num = read();
        update(i, num);
    }
    char op[6];
    int a, b;
    while(M--){
        scanf("%s", op);
        a = read();
        b = read();
        if(op[0] == 'Q'){
            printf("%d\n", (query(b)-query(a-1)));
        }
        else{
            update(a, b);
        }
    }
    return 0;
}
士兵杀敌(三)
时间限制:2000 ms  |  内存限制:65535 KB
难度:5
描述
南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。

所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。

现在,请你写一个程序,帮小工回答南将军每次的询问吧。

注意,南将军可能询问很多次。

输入
只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1<N<=100000,1<Q<=1000000)
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出
对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。
样例输入
5 2
1 2 6 9 3
1 2
2 4
样例输出
1
7

之前写了线段树过不了,这里学了一下ST算法,mark一下。
一篇很好的ST算法,这里是传送门

初始化的转移方程 F[i,j] = max( F[i, j-1],  F[i+(1<<(j-1),j-1] );
查询区间长度为end - start + 1, 这里可以取k = log2(i+j-1),然后向下取整,
查询方程为 F[start, end] = max( F[start, k], F[end-(1<<k)+1, k]);
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define scini(n) scanf("%d", &n)
#define scinl(n) scanf("%lld", &n)
#define scinii(n, m) scanf("%d%d", &n, &m)
#define scinll(n, m) scanf("%lld%lld", &n, &m)
#define scouti(n) printf("%d\n", n);
#define scoutii(n, m) printf("%d\n%d\n", n, m);

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 100100;
using namespace std;

inline int 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;
}
int dpmax[maxn][20]; //开20的原因是2^20刚好>100000, 这里根据题目给的值的大小取。
int dpmin[maxn][20];

void rmq(int end, int limits)  //O(nlogn)初始化
{
    for(int j = 1; j < limits; ++j){
        for(int i = 1; i <= end; ++i){
            if(i+(1<<j)-1 <= end){     //控制越界
                dpmax[i][j] = max(dpmax[i][j-1], dpmax[i+(1<<(j-1))][j-1]);
                dpmin[i][j] = min(dpmin[i][j-1], dpmin[i+(1<<(j-1))][j-1]);
            }
        }
    }
}

int main()
{
   // fin;
    int N, M;
    N = read();
    M = read();
    for(int i = 1; i <= N; ++i){
        dpmax[i][0] = read();
        dpmin[i][0] = dpmax[i][0];
    }
    rmq(N, (log2(N)+1));  //这里的log2(N)+1我是用来控制区间初始化的大小的。
    while(M--){  //O(1)查询区间最大最小值
        int start, end;
        start = read();
        end = read();
        int k = floor(log2(end-start+1));
        int max_ = max(dpmax[start][k], dpmax[end-(1<<k)+1][k]);
        int min_ = min(dpmin[start][k], dpmin[end-(1<<k)+1][k]);
     //   scoutii(max_, min_);
        scouti((max_-min_));
    }
    return 0;
}

优化后的代码,时间效率明显提升

const int maxn = 100100;
inline int 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;
}
int dpmax[20][maxn];
int dpmin[20][maxn];
void rmq(int end, int limits)
{
    for(int i = 1; i < limits; ++i){
        for(int j = 1; j <= end; ++j){
            if(j+(1<<i)-1 <= end){
                dpmax[i][j] = max(dpmax[i-1][j], dpmax[i-1][j+(1<<i>>1)]);//这里的1<<i>>1其实就是1<<(i-1);
                dpmin[i][j] = min(dpmin[i-1][j], dpmin[i-1][j+(1<<i>>1)]);
            }
        }
    }
}
士兵杀敌(四)
时间限制:2000 ms  |  内存限制:65535 KB
难度:5
描述
南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧。

假设起始时所有人的军功都是0.

输入
只有一组测试数据。
每一行是两个整数T和M表示共有T条指令,M个士兵。(1<=T,M<=1000000)
随后的T行,每行是一个指令。
指令分为两种:
一种形如
ADD 100 500 55 表示,第100个人到第500个人请战,最终每人平均获得了55军功,每次每人获得的军功数不会超过100,不会低于-100。
第二种形如:
QUERY 300 表示南将军在询问第300个人的军功是多少。
输出
对于每次查询输出此人的军功,每个查询的输出占一行。
样例输入
4 10
ADD 1 3 10
QUERY 3
ADD 2 6 50
QUERY 3
样例输出
10
60

树状数组插线,单点查询


#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define scini(n) scanf("%d", &n)
#define scinl(n) scanf("%lld", &n)
#define scinii(n, m) scanf("%d%d", &n, &m)
#define scinll(n, m) scanf("%lld%lld", &n, &m)
#define scout(n) printf("%d\n", n);

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 100010;
using namespace std;

int res[1000100];
int N;
int 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;
}
void update(int i, int add)
{
    while(i > 0){
        res[i] += add;
        i -= lowbit(i);
    }
}
int query(int i)
{
    int ret = 0;
    while(i <= N){
        ret += res[i];
        i += lowbit(i);
    }
    return ret;
}
int main()
{
    int M;
    N = read();
    M = read(); 
    mes(res, 0);
    char op[6];
    int begin, end, add;
    while(M--){
        scanf("%s", op);
        if(op[0] == 'A'){
            begin = read();
            end = read();
            add = read();
            update(begin-1, -add);
            update(end, add);
        }
        else{
            begin = read();
            scout(query(begin));
        }
    }
    return 0;
}        
士兵杀敌(五)
时间限制:2000 ms  |  内存限制:65535 KB
难度:5
描述
南将军麾下有百万精兵,现已知共有M个士兵,编号为0~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情。

在这样的情况下,南将军却经常会在许多次战役之后询问军师小工第i号士兵到第j号士兵所有人的总军功数。

请你帮助军师小工回答南将军的提问。

输入
只有一组测试数据
第一行是三个整数N,C,Q(1<=N,C,Q<=1000000),其中N表示士兵的总数。
随后的C行,每行有三个整数Mi,Ni,Ai(0<=Mi<=Ni<=N,0<=Ai<=100),表示从第Mi号到第Ni号士兵所有人平均增加了Ai的军功。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出
请对每次询问输出m号士兵到第n号士兵的总军功数,由于该数值可能太大,请把结果对10003取余后输出
样例输入
5 3 2
1 3 2
2 4 1
5 5 10
1 5
2 3
样例输出
19
6

这道题,十分鬼畜,怎么说呢,你看看M个士兵编号0~M,看样例确实是1~M的,可是交上去wa了,然后加上0~M的情况,就a了…….,具体看代码。
其实就是树状数组插线然后数组储存前缀和,然后查询。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define scini(n) scanf("%d", &n)
#define scinl(n) scanf("%lld", &n)
#define scinii(n, m) scanf("%d%d", &n, &m)
#define scinll(n, m) scanf("%lld%lld", &n, &m)
#define scouti(n) printf("%d\n", n);
#define scoutii(n, m) printf("%d\n%d\n", n, m);

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1000100;
using namespace std;

inline int 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;
}
ll ret[maxn];
int res[maxn];
int N;
int Other = 0;
void update(int i, int add) 
{
    while(i > 0){
        res[i] += add;
        i -= lowbit(i);
    }
}

ll query(int i) //单点求值
{
    ll ret = 0;
    while(i <= N){
        ret += res[i];
        i += lowbit(i);
    }
    return ret;
}

int main()
{
    // fin;
    int C, Q;
    mes(res, 0);
    mes(ret, 0);
    N = read();
    C = read();
    Q = read();
    int start, end, add;
    while(C--){
        start = read();
        end = read();
        add = read();
        if(0 == start){
            Other += add;
        }
        update(start-1, -add);  //这里是插线
        update(end, add);
    }
    for(int i = 0; i <= N; ++i){  //储存前缀和
        int a, b;
        a = i;
        b = query(i);  //求ret[i]的值
        if(0 == a){  //0的情况
            b = 0;   //query是算1~N的,所以0的情况要单独说,不然就死循环了。
            ret[i] = b;
        }
        else{
            ret[i] = b + ret[i-1];
        }
    }
    while(Q--){
        start = read();
        end = read();
        if(0 == start){ //0的情况
            printf("%lld\n", (ret[end]+Other)%10003); //0也有分配军工的,所以把所有有0的军工的情况加起来单独算。
        }
        else{
            printf("%lld\n", (ret[end]-ret[start-1])%10003);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值