原题直通车: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;
}