POJ 3468 A Simple Problem with Integers


线段树基础题,除线段树外至少还有2种做法:树状数组,Splay

A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 54111 Accepted: 16267
Case Time Limit: 2000MS

Description

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

Source

[Submit]   [Go Back]   [Status]   [Discuss]




树状数组的改段求段操作:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2100100;
int n,q;
long long int b[maxn],c[maxn];
void init()
{
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
}
int lowbit(int x)
{
    return x&(-x);
}
void add_b(int p,long long int v)
{
    for(int i=p;i;i-=lowbit(i)) b[i]+=v;
}
void add_c(int p,long long int v)
{
    for(int i=p;i<maxn;i+=lowbit(i)) c[i]+=p*v;
}
long long int sum_b(int p)
{
    long long int ret=0;
    for(int i=p;i<maxn;i+=lowbit(i)) ret+=b[i];
    return ret;
}
long long int sum_c(int p)
{
    long long int ret=0;
    for(int i=p;i;i-=lowbit(i)) ret+=c[i];
    return ret;
}
void ADD(int L,int R,long long int v)
{
    add_b(R,v);
    add_c(R,v);
    if(L-1)
    {
        add_b(L-1,-v);
        add_c(L-1,-v);
    }
}
long long int sUm(int p)
{
    if(p==0) return 0;
    return sum_b(p)*p+sum_c(p-1);
}
long long int SUM(int L,int R)
{
    return sUm(R)-sUm(L-1);
}
int main()
{
while(scanf("%d%d",&n,&q)!=EOF)
{
    init();
    for(int i=1;i<=n;i++)
    {
        int v;
        scanf("%d",&v);
        ADD(i,i,v);
    }
    while(q--)
    {
        char str[10];
        scanf("%s",str);
        if(str[0]=='Q')
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%I64d\n",SUM(l,r));
        }
        else if(str[0]=='C')
        {
            int l,r;
            long long int v;
            scanf("%d%d%I64d",&l,&r,&v);
            ADD(l,r,v);
        }
    }
}
    return 0;
}

Splay的延时标记:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long int LL;
const int maxn=100100;
const int INF=0x3f3f3f3f;
#define Key_value  ch[ch[root][1]][0]

int pre[maxn],ch[maxn][2],key[maxn],size[maxn],a[maxn];
int n,m;
LL add[maxn],sum[maxn];
int root,tot;

/*******************debug*******************/
void Debug(int x)
{
    if(x)
    {
        Debug(ch[x][0]);
        cout<<"节点:"<<x<<" Key: "<<key[x]<<" left_son: "<<ch[x][0]<<" right_son: "<<ch[x][1]
        <<" size: "<<x<<" Sum: "<<sum[x]<<endl;
        Debug(ch[x][1]);
    }
}
/*******************************************/

void NewNode(int& r,int father,int k)
{
    r=++tot;
    pre[r]=father;
    ch[r][0]=ch[r][1]=add[r]=0;
    sum[r]=key[r]=k;
    size[r]=1;
}

void Update_Add(int x,int v)
{
    if(x==0) return ;
    sum[x]+=(LL)size[x]*v;
    key[x]+=v;
    add[x]+=v;
}

void Push_Up(int x)
{
    sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x];
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}

void Push_Down(int x)
{
    if(add[x])
    {
        Update_Add(ch[x][0],add[x]);
        Update_Add(ch[x][1],add[x]);
        add[x]=0;
    }
}

void Build(int &x,int l,int r,int father)
{
    if(l>r) return ;
    int m=(l+r)>>1;
    NewNode(x,father,a[m]);
    Build(ch[x][0],l,m-1,x);
    Build(ch[x][1],m+1,r,x);
    Push_Up(x);
}

void Init()
{
    tot=root=0;
    ch[root][0]=ch[root][1]=pre[root]=key[root]=sum[root]=add[root]=size[root]=0;
    NewNode(root,0,-INF);
    NewNode(ch[root][1],root,INF);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    Build(Key_value,1,n,ch[root][1]);
    Push_Up(ch[root][1]);
    Push_Up(root);
}

void Rotate(int x,int kind)
{
    int y=pre[x];
    Push_Down(y);
    Push_Down(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    Push_Up(y);
}

void Splay(int r,int goal)
{
    Push_Down(r);
    while(pre[r]!=goal)
    {
        if(pre[pre[r]]==goal)
        {
            Push_Down(pre[r]);
            Push_Down(r);
            Rotate(r,ch[pre[r]][0]==r);
        }
        else
        {
            Push_Down(pre[pre[r]]);
            Push_Down(pre[r]);
            Push_Down(r);
            int y=pre[r];
            int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==r)  Rotate(r,!kind);
            else Rotate(y,kind);
            Rotate(r,kind);
        }
    }
    Push_Up(r);
    if(goal==0) root=r;
}

int Get_Kth(int r,int x)
{
    Push_Down(r);
    int t=size[ch[r][0]]+1;
    if(t==x) return r;
    else if(t>x) return Get_Kth(ch[r][0],x);
    else return Get_Kth(ch[r][1],x-t);
}

void ADD(int l,int r,int v)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    Update_Add(Key_value,v);
    Push_Up(ch[root][1]);
    Push_Up(root);
}

LL Query(int l,int r)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    return sum[Key_value];
}

int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
    Init();
    char op[20];
    while(m--)
    {
        scanf("%s",op);
        int a,b,c;
        if(op[0]=='Q')
        {
            scanf("%d%d",&a,&b);
            printf("%I64d\n",Query(a,b));
        }
        else if(op[0]=='C')
        {
            scanf("%d%d%d",&a,&b,&c);
            ADD(a,b,c);
        }
    }
}
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值