1. 程式人生 > >ACM-ICPC 2018 徐州賽區網路預賽(I + H)(水模擬 + 線段樹)

ACM-ICPC 2018 徐州賽區網路預賽(I + H)(水模擬 + 線段樹)

I

題意

給定一個字串s和一個字元L,將所有的 |(int)(Ls[i])| 轉化為一個兩位數後,按順序拼接在一起,問,這個拼接而成的新序列,去掉前導0後的長度是多少

思路

按照模擬去實現一下過程就可以,可以計算前導零的個數,就不用算出所有的值了,現給出一種純模擬的寫法

程式碼


int  a[maxn];
char s[maxn], ch;

int main()
{
    int T;
    sd(T);
    while(T--){
        int n, now = 0, ans = 1;
        scanf("%d %c
"
, &n, &ch); if(n==0) { puts("1"); continue; } ss(s); rep(i, 0, n){ int t = abs((int)(ch-s[i])); a[now++] = t/10; a[now++] = t%10; } rep(i, 0, 2*n){ if(a[i] != 0) { ans = 2
*n-i; break; } } pd(ans); } return 0; }

H

題意

給出一個長度為 n 的序列,q 次詢問:
1lr 詢問a[l]×L+a[l+1]×(L1)++a[r1]×2+a[r],其中L[l,r]區間的長度。
2xk表示將序列中第 x 個數設定為 k

思路

題目是一眼看過去就知道是線段樹的題,那麼就變成了我們怎麼往線段樹上去考慮了。
從線段樹的思想入手,線段樹能解決區間問題的原因是,我們可以對區間維護的值進行合併,而這樣的一個類似梯度的求和,我們相當於維護了兩個區間的和

sum, 區間的”梯度和”(所求部分)ans, 以及區間的長度 len, 用線段樹來表示的話,我們可以得到這樣一個維護方程

tree[i].ans=tree[i<<1].ans+tree[i<<1|1].ans+tree[i<<1].sum×tree[i<<1|1].len 那麼根據這個式子,我們就可以維護所求部分,已經查詢的分段了。

程式碼

struct Node{
    int l, r, len;
    ll sum, ans;
}tree[maxn<<2];              //開四倍空間
ll num[maxn];                //數值陣列

void build(int i, int l, int r){
    tree[i].l = l;
    tree[i].r = r;
    tree[i].len = (r-l+1);
    if(l == r){
        tree[i].sum = num[l];
        tree[i].ans = num[l];
        return ;
    }

    int mid = (l+r)>>1;
    build(i<<1, l, mid);
    build(i<<1|1, mid+1, r);    //子樹建樹後更新特徵值
    tree[i].sum = tree[i<<1].sum + tree[i<<1|1].sum;
    tree[i].ans = tree[i<<1].ans + tree[i<<1|1].ans + tree[i<<1].sum*tree[i<<1|1].len;
    return ;
}

void setx(int i, int x, int k){  // num[x] = k
    if(tree[i].l == tree[i].r) {
        tree[i].sum = k;
        tree[i].ans = k;
        return ;
    }
    int mid = (tree[i].l+tree[i].r)>>1;
    if(x <= mid) setx(i<<1, x, k);
    else setx(i<<1|1, x, k);
    tree[i].sum = tree[i<<1].sum + tree[i<<1|1].sum;
    tree[i].ans = tree[i<<1].ans + tree[i<<1|1].ans + tree[i<<1].sum*tree[i<<1|1].len;
}


ll querys(int i, int l, int r) {
    if(tree[i].l==l && tree[i].r==r)
        return tree[i].sum;

    int mid = (tree[i].l+tree[i].r)>>1;
    if(mid >= r)
        return querys(i<<1, l, r);
    else if(mid < l)
        return querys(i<<1|1, l, r);
    else
        return querys(i<<1, l, mid) + querys(i<<1|1, mid+1, r) ;
}

ll querya(int i, int l, int r) {
    if(tree[i].l==l && tree[i].r==r)
        return tree[i].ans;

    int mid = (tree[i].l+tree[i].r)>>1;
    if(mid >= r)
        return querya(i<<1, l, r);
    else if(mid < l)
        return querya(i<<1|1, l, r);
    else
        return querya(i<<1, l, mid) + querya(i<<1|1, mid+1, r) + querys(i<<1, l, mid)*(r-mid);
}


int main() {

    int n, q;
    sdd(n, q);
    rep(i, 1, n+1)
        sld(num[i]);
    build(1, 1, n);
    rep(i, 0, q) {
        int op, l, r;
        sddd(op, l, r);
        if(op == 1){
            printf("%lld\n", querya(1, l, r));
        }
        else {
            setx(1, l, r);
        }
    }

    return 0;
}