士兵杀敌(四)

士兵杀敌(四)

时间限制: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

 

做法一:树状数组:主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。

void Update(int i,int value,int n)  //从前往后更新
{
       while(i<=n)
       {
              C[i]+=value;
              i+=i&(-i);
       }
}
int sum(int x)          //求和 0到x 
{  
    int ans=0;  
    while(x>0)  
    {  
        ans+=a[x];  
        x-=x&(-x);  
    }  
    return ans;  
}  
void update(int star,int value)  //从后往前更新
{  
    while(star>0)  
    {  
        add[star]+=value;  
        star-=star&(-star);  
    }  
}  
int sum(int end)  
{  
    int ans=0;  
    while(end<=m)  
    {  
        ans+=add[end];  
        end+=end&(-end);  
    }  
    return ans;  
}  

 

插线问点:向[star,end]这个区间加value,就可以看做是向[0,end]加value,然后向[0,star-1]加-value。利用update实现,然后就可以问点了,用sum函数问

 

插点问线:直接update

 

插线问线:首先是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delta[l] 和 delta[r + 1] 即可(就是差分的思路)

     查询的时候是查询区间 [l, r] 的和 即sum[r] - sum[l - 1] 所以现在的问题是求sum[i]

 

#include<stdio.h>
#include<string.h>
int C[1000005],t,m;
void Update(int star,int value)  //A[i]的改变值为value
{
       while(star<=m)
       {
              C[star]+=value;
              star+=star&(-star);
       }
}
int Sum(int x)          //求和 0到x 
{  
    int ans=0;  
    while(x>0)  
    {  
        ans+=C[x];  
        x-=x&(-x);  
    }  
    return ans;  
}  
int main()
{
    int i,j;
    char str[15];
    scanf("%d %d",&t,&m);
    memset(C,0,sizeof(C));
    for(i=1;i<=t;i++)
    {
        scanf("%s",str);
        if(strcmp(str,"ADD")==0)
        {
            int l,r,c;
            scanf("%d %d %d",&l,&r,&c);
            Update(l,c);  
            Update(r+1,-c);  
        }
        else if(strcmp(str,"QUERY")==0)
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",Sum(x));    
        }
    }
    return 0;
}

或者

 

 
#include<stdio.h>
#include<string.h>
int C[1000005],t,m;
void update(int star,int value)  
{  
    while(star>0)  
    {  
        C[star]+=value;  
        star-=star&(-star);  
    }  
}  
int sum(int end)  
{  
    int ans=0;  
    while(end<=m)  
    {  
        ans+=C[end];  
        end+=end&(-end);  
    }  
    return ans;  
}  
int main()
{
    int i,j;
    char str[15];
    scanf("%d %d",&t,&m);
    memset(C,0,sizeof(C));
    for(i=1;i<=t;i++)
    {
        scanf("%s",str);
        if(strcmp(str,"ADD")==0)
        {
            int l,r,c;
            scanf("%d %d %d",&l,&r,&c);
            update(r,c);  
            update(l-1,-c);  
        }
        else if(strcmp(str,"QUERY")==0)
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",sum(x));    
        }
    }
    return 0;
}        

 

做法二:线段树

 

 

做法三:差分数组(本题不推荐)

差分数组修改一次区间数据,就要维护一次数组  ,所以适用于多次修改后查询

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

int d[1000001];
int a[1000001];
int sum[1000001];
int main()
{
    int t,m,i,j,x;
    char str[10];
    scanf("%d %d",&t,&m);
    for(i=0;i<=m;i++)    a[i] = 0;
    for(i=1;i<=m;i++)   d[i]=a[i]-a[i-1];
    d[0] = a[0];
    for(j=1;j<=t;j++)
    {
        scanf("%s",str);
        if(strcmp(str,"ADD")==0)
        {
            int l,r,c;
            scanf("%d %d %d",&l,&r,&c);
            d[l] += c;
            d[r+1] -=c;
        }
        else if(strcmp(str,"QUERY")==0)
        {
            scanf("%d",&x);    
            for(i=0;i<=x;i++)    sum[i] = 0;
            for (i = 1; i <= x; i++)
               {
                if(i==1)    sum[i] = d[i];
                else        sum[i] = d[i] + sum[i-1];
            }
            printf("%d\n",sum[x]);        
        }
    }    
    return 0;
}

 

posted @ 2017-12-06 00:59  萌新上路  阅读(113)  评论(0编辑  收藏  举报