【树状数组】HDU_3854_Glorious Array

原题直通车:HDU_3854_Glorious Array

题意: 有n个结点,权值为len[i],结点颜色分黑白两种(1/0),仅异色点可相连。

       对于点对a、b(异色)的边的权值=min(len[j], a<=j<=b); 

有m次操作: 输入0  x时表示更改第x个结点的颜色,输入1时表示询问:满足边权值小于k的点对的数量。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000005;
int n, m, k, sum_1;
__int64 ans;
int col[maxn], len[maxn], num[maxn];
int pl[maxn], pr[maxn];  // pl[i]、pr[i]分别为第i个点的左右第一个满足len<k的下标
__int64 sum(int x) {
    int ret=0;
    while(x>0) ret+=num[x], x-=x&(-x);
    return ret;
}
void add(int x, int d) {
    while(x<=n) num[x]+=d, x+=x&(-x);
}
void work() {
    for(int i=1; i<=n; ++i)
        if(len[i]<k) {
            __int64 l1=sum(i-1)-sum(pl[i]), l0=i-1-pl[i]-l1, r1=sum_1-sum(i), r0=n-i-r1;
            ans+=l1*r0+l0*r1;
            if(col[i]) ans+=l0+r0;
            else ans+=l1+r1;
        }
}
void update() {
    int x; scanf("%d",&x);
    if(len[x]<k) {
        if(col[x]) ans+=2*sum_1-n-1; // 1: sum_1-1    0: n-sum_1
        else ans+=n-2*sum_1-1;       // 1: sum_1      0: n-sum_1-1
    } else {
        __int64 l1=sum(pl[x]), l0=pl[x]-l1, r1=sum_1-sum(pr[x]-1), r0=n-pr[x]+1-r1;
        if(col[x]) ans+=l1+r1-l0-r0;
        else ans+=l0+r0-l1-r1;
    }
    add(x, (col[x]?-1:1));
    sum_1+=(col[x]?-1:1);
    col[x]=(col[x]+1)%2;
}
int main() {
    int T; scanf("%d",&T);
    while(T--) {
        sum_1=ans=0;
        memset(num, 0, sizeof(num));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1, t=0; i<=n; ++i) {
            scanf("%d",len+i);
            pl[i]=t;
            if(len[i]<k) t=i;
        }
        for(int i=n, t=n+1; i>=1; --i) {
            pr[i]=t;
            if(len[i]<k) t=i;
        }
        for(int i=1; i<=n; ++i) {
            scanf("%d",col+i);
            if(col[i]) add(i, 1), sum_1++;
        }
        work();
        while(m--) {
            int cmd; scanf("%d",&cmd);
            if(cmd) printf("%I64d\n",ans);
            else update();
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值