hdu 1166 敌兵布阵 + Dairy

Today is 4.30,the second day in 2S.
遇见了一个十分humorous的把妹老师。嗯南方人。所化四泽阳的。

说正事:
今天第一题,两种解,打算好好写写,但是据说我写的东西跟八级阅读题一样。。【【【黑线

第一种方法:

树状数组。

其神奇所在,大概是lowbit数组。
hdu 1166 敌兵布阵 + Dairy_第1张图片

由图可知,c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4……
一次类推可知,i是奇数时,ai=ci;i是偶数是(c6=a5+a6),要看i里含2
的几次幂的因数。比如c4里是2的2次幂,所以是a1+a2+a3+a4;c6只含2,所以是a5+a6; 所以我们有有公式:cn=a(n-2^k+1)+………+an(其中 k 为 n 的二进制表示中从右往左数的 0 的个数)。 eg:6的二进制是110,那就是6-2^1+1,所以就是a5+a6。
2^k怎么求呢?

int lowbit(int x){
    return x&(-x);
}

如上,其实是x&(~(x-1))…..
举个例子:
6 110
~(5) 010
6&~(5) 010 ==2 !

剩下的简单的多了,一个是插入操作,还有一个修改。

看代码好了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 50005
int n;
int a[N],c[N];
int lowbit(int x){
    return x&(-x);
}
void add(int i,int w){
    while(i<=n){
        c[i]+=w;
        i=i+lowbit(i);   //增加是要往后跳的!!
    }
}
int sum(int i){
    int sum=0;
    while(i>0){
        sum+=c[i];
        i=i-lowbit(i);  //求和则是往前。
    }
    return sum;
}
int main()  
{  
    int t,i,tmp,x,y,cases=1;  
    char op[100];  
    scanf("%d",&t);  
    while(t--)  
    {  
        printf("Case %d:\n",cases++);  
        memset(a,0,sizeof(a)); 
        memset(c,0,sizeof(c));  //记得要清空数组!!
        scanf("%d",&n);  
        for(i=1;i<=n;i++)  
        {  
            scanf("%d",&tmp);  
            add(i,tmp);  
        }   
        while(scanf("%s",op)&& op[0]!='E')  
        {  
            scanf("%d%d",&x,&y);  
            if(op[0]=='A')  
                add(x,y);  
            else if(op[0]=='S')  
                add(x,-y);  
            else  
                printf("%d\n",sum(y)-sum(x-1));  
        }  
    } 
    return 0;  
} 
/*1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End */

第二种方法:

线段树:
没什么解释的?

直接看好了

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
struct Line{
    int left,right;
    int val;
}line[200001];
int n,ans,jy,cases=1;
int c[200001];
char op[11];
void build(int l,int r,int num){
    if(l == r) 
    {
        scanf("%d",&line[num].val); 
        return;
    }
        line[num].left=l;
        line[num].right=r;
        int mid=(l+r)/2;
        build(l,mid,2*num);
        build(mid+1,r,2*num+1);
        line[num].val=line[num*2].val+line[num*2+1].val;//更新父亲节点 
}
void modify(int a,int b,int s,int t,int num){
    if(s == t){
        line[num].val+=b;
        return;
    }    
    int mid=(s+t)/2;
    if(a<=mid) modify(a,b,s,mid,num*2);
    else modify(a,b,mid+1,t,num*2+1);
    line[num].val=line[num*2].val+line[num*2+1].val;
}

int query(int a,int b,int s,int t,int num){
//    printf("%d %d %d\n",a,b,num);
    if(a<=s && b>=t){
         return line[num].val;
    //printf("lal %d\n",line[num].val);
}
    int mid=(s+t)/2;
    int res=0;
    if(a<=mid) res+=query(a,b,s,mid,num*2);
    //printf("%d\n",res);
    if(b>mid)  res+=query(a,b,mid+1,t,num*2+1);
    //printf("%d\n",res);
    return res; 
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        printf("Case %d:\n",cases++);
        scanf("%d",&n);
        build(1,n,1);
    /* for(int i=1;i<=10;i++){ printf("%d \n",line[i].val); }*/
        int x,y;
        //while(scanf("%s",op) && op[0]!='E'){
        while(1){
            scanf("%s",op);
            if(op[0] == 'E') break;
            //scanf("%d%d",&x,&y);
            if(op[0] == 'A') {
                scanf("%d%d",&x,&y);
                modify(x,y,1,n,1);
            }
            if(op[0] == 'S') {
                scanf("%d%d",&x,&y);
                modify(x,-y,1,n,1);
            }
            if(op[0] == 'Q'){
                scanf("%d%d",&x,&y);
                printf("%d\n",query(x,y,1,n,1));
            }
        }
    }
}

啦啦啦,拖到现在才写完,马上就要上课了。

你可能感兴趣的:(HDU)