2013-05-06 20:23:40Morris

[UVA][線段樹、zkw、BIT] 12086 - Potentiometers

B

Potentiometers

Input: Standard Input

Output: Standard Output

A potentiometer, or potmeter for short, is an electronic device with a variable electric resistance. It has two terminals and some kind of control mechanism (often a dial, a wheel or a slide) with which the resistance between the terminals can be adjusted from zero (no resistance) to some maximum value. Resistance is measured in Ohms, and when two or more resistors are connected in series (one after the other, in a row), the total resistance of the array is the sum of the resistances of the individual resistors.

In this problem we will consider an array of N potmeters, numbered 1 to N from left to right. The left terminal of some potmeter numbered x is connected to the right terminal of potmeter x-1, and its right terminal to the left terminal of potmeter x+1. The left terminal of potmeter 1 and the right terminal of potmeter N are not connected.

Initially all the potmeters are set to some value between 0 and 1000 Ohms. Then we can do two things:

  • Set one of the potmeters to another value.
  • Measure the resistance between two terminals anywhere in the array.
Input

The input consists less than 3 cases. Each case starts with N, the number of potmeters in the array, on a line by itself. N can be as large as 200000. Each of next N lines contains one numbers between 0 and 1000, the initial resistances of the potmeters in the order 1 to N. Then follow a number of actions, each on a line by itself. The number of actions can be as many as 200000. There are three types of action:

  • "S x r" - set potmeter x to r Ohms. x is a valid potmeter number and r is between 0 and 1000.
  • "M x y" - measure the resistance between the left terminal of potmeter x and the right terminal of potmeter y. Both numbers will be valid and x is smaller than or equal to y.
  • "END" - end of this case. Appears only once at the end of a list of actions.

A case with N=0 signals the end of the input and it should not be processed.

 

Output

For each case in the input produce a line "Case n:", where n is the case number, starting from 1.
For each measurement in the input, output a line containing one number: the measured resistance in Ohms. The actions should be applied to the array of potmeters in the order given in the input.
Print a blank line between cases.

 

Warning: Input Data is pretty big (~  8 MB) so use faster IO.

 

 


Sample Input                             Output for Sample Input

3

100

100

100

M 1 1

M 1 3

S 2 200

M 1 2

S 3 0

M 2 3

END

10

1

2

3

4

5

6

7

8

9

10

M 1 10

END

0

 

Case 1:

100

300

300

200

 

Case 2:

55


Problem setter: Joachim Wulff, Special Thanks: Shahriar Manzoor


基本上需要兩種操作 (1) 求區間總合 (2) 單點更新

最簡單的遞迴線段樹寫法

#include <stdio.h>
int A[(1<<18)+1], ST[(1<<19)+1];
void setTree(int k, int l, int r) {
    if(l == r)
        ST[k] = A[l];
    else if(l < r) {
        int m = (l+r)>>1;
        setTree(k<<1, l, m);
        setTree(k<<1|1, m+1, r);
        ST[k] = ST[k<<1] + ST[k<<1|1];
    } else
        ST[k] = 0;
}
int query(int k, int l, int r, int &x, int &y) {
    if(l > r)   return 0;
    if(x <= l && r <= y)
        return ST[k];
    int m = (l+r)>>1;
    if(y <= m)
        return query(k<<1, l, m, x, y);
    else if(x > m)
        return query(k<<1|1, m+1, r, x, y);
    else
        return query(k<<1, l, m, x, y)+
                query(k<<1|1, m+1, r, x, y);
}
void modify(int k, int l, int r, int &x, int &y) {
    if(l > r)   return ;
    if(l == r && l == x) {
        ST[k] = y;
        return;
    }
    int m = (l+r)>>1;
    if(x <= m)
        modify(k<<1, l, m, x, y);
    else
        modify(k<<1|1, m+1, r, x, y);
    if(l != r)
        ST[k] = ST[k<<1] + ST[k<<1|1];
}
int main() {
    int n, x, y, i;
    int cases = 0;
    char op[10], cmd[50];
    while(scanf("%d", &n) == 1 && n) {
        for(i = 1; i <= n; i++)
            scanf("%d", &A[i]);
        while(getchar() != '\n');
        setTree(1, 1, n);
        if(cases)   puts("");
        printf("Case %d:\n", ++cases);
        while(gets(cmd)) {
            if(cmd[0] == 'E')
                break;
            sscanf(cmd, "%s %d %d", op, &x, &y);
            if(op[0] == 'M')
                printf("%d\n", query(1, 1, n, x, y));
            else
                modify(1, 1, n, x, y);
        }
    }
    return 0;
}

zkw 線段樹寫法

#include <stdio.h>
#include <string.h>
#define node 262144
int A[node], tree[node<<1], M;
void setTree() {
    int i;
    for(i = 2*M-1; i > 0; i--) {
        if(i >= M) { //leaf
            tree[i] = A[i-M];
        } else {
            tree[i] = tree[i<<1]+tree[(i<<1)+1];
        }
    }
}
int query(int s, int t) {
    static int i;
    int ans = 0;
    for(s = s+M-1, t = t+M+1; (s^t) != 1;) {
        if(~s&1)
            ans += tree[s^1];
        if(t&1)
            ans += tree[t^1];
        s >>= 1, t >>= 1;
    }
    return ans;
}
void singleModify(int s, int v) {
    s += M;
    while(s) {
        tree[s] += v;
        s >>= 1;
    }
}
int main() {
    int n, x, y, i;
    int cases = 0;
    char op[10], cmd[50];
    while(scanf("%d", &n) == 1 && n) {
        for(M = 1; M < n+2; M <<= 1);
        memset(A, 0, sizeof(A));
        for(i = 1; i <= n; i++)
            scanf("%d", &A[i]);
        while(getchar() != '\n');
        if(cases)   puts("");
        printf("Case %d:\n", ++cases);
        setTree();
        while(gets(cmd)) {
            if(cmd[0] == 'E')
                break;
            sscanf(cmd, "%s %d %d", op, &x, &y);
            if(op[0] == 'M')
                printf("%d\n", query(x, y));
            else {
                singleModify(x, y-A[x]);
                A[x] = y;
            }
        }
    }
    return 0;
}

直接換個資料結構 binary indexed tree 掃一次。
速度跟 zkw 差不多。

#include <stdio.h>
int BIT[(1<<18)+1], A[1<<18];
int query(int idx) {
    static int sum;
    sum = 0;
    while(idx) {
        sum += BIT[idx];
        idx -= idx&(-idx);
    }
    return sum;
}
void modify(int idx, int L, int v) {
    while(idx <= L) {
        BIT[idx] += v;
        idx += idx&(-idx);
    }
}
int main() {
    int n, x, y, i;
    int cases = 0;
    char op[10], cmd[50];
    while(scanf("%d", &n) == 1 && n) {
        for(i = 1; i <= n; i++) {
            scanf("%d", &A[i]);
            BIT[i] = 0;
        }
        for(i = 1; i <= n; i++)
            modify(i, n, A[i]);
        while(getchar() != '\n');
        if(cases)   puts("");
        printf("Case %d:\n", ++cases);
        while(gets(cmd)) {
            if(cmd[0] == 'E')
                break;
            sscanf(cmd, "%s %d %d", op, &x, &y);
            if(op[0] == 'M')
                printf("%d\n", query(y) - query(x-1));
            else {
                modify(x, n, y-A[x]);
                A[x] = y;
            }
        }
    }
    return 0;
}