您的位置:首页 > 其它

codeforces 400e 线段树

2014-03-09 02:34 176 查看
    N个数组成a[1][]这个序列,定义a[i+1][j]=a[i][j]&a[i][j+1],根据此公式可以推出一个数字三角形,现有m个操作,每次操作x,y把a[1][x]的数修改成y,并且输出修改后新的数字三角形中所有数的和。

    首先要确定一点,连续k个1相连,构成的三角形中数字和(权值)是sum(1..k),那么对于原题中的三角形,我们可以按位拆分出最多17三角形(因为最大的数10W<2^17),那么现在要做的就是在每次修改后,求出每个三角形中有多少组相连的1,并把和累加。可以用17棵线段树来维护这17个三角形,每棵线段树维护sum[],pre[],suff[]三个变量分别表示所有组相连的1产生的权值和,前缀有多少个1相连,后缀有多少个1相连,那么在pushup的时候,若左孩子的后缀和右孩子的前缀都不为0,那么这次合并就会产生额外的权值,该变量为+sum(1..suff+pre)-sum(1..suff)-sum(1...pre),同事更新当前pre和suff的值即可。查询的时候因为查的是整个区间,所以直接返回sum[1]就可以了,最后把得到的从0--16位所有的权值和,按二进制组合一下就是最后的答案..

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
using namespace std;
typedef long long ll;
const int up=17;
const int maxn=101000;
ll sumpre[maxn<<2];
int n,m,k;
int a[maxn<<2];
bool cc[20][maxn<<2];
bool mc[20];
struct segmenttree
{
ll suff[maxn<<2],pre[maxn<<2],sum[maxn<<2];

void init()
{
memset(suff,0,sizeof suff);
memset(pre,0,sizeof pre);
memset(sum,0,sizeof sum);
}
void pushup(int id,ll la,ll lb)
{
if (suff[id<<1] && pre[id<<1|1])
{

sum[id]=sum[id<<1]+sum[id<<1|1]+sumpre[suff[id<<1]+pre[id<<1|1]]-sumpre[suff[id<<1]]-sumpre[pre[id<<1|1]];
}
else
{
sum[id]=sum[id<<1]+sum[id<<1|1];
}
if (la==pre[id<<1])
{
pre[id]=la+pre[id<<1|1];
}
else pre[id]=pre[id<<1];

if (lb==suff[id<<1|1])
{
suff[id]=suff[id<<1]+lb;
}
else suff[id]=suff[id<<1|1];
}
void modify(int pos,int c,int id,int l,int r)
{
if (l==r)
{
sum[id]=suff[id]=pre[id]=c;
return;
}
int m=(l+r)>>1;
if (pos<=m) modify(pos,c,lson);
if (pos>m) modify(pos,c,rson);
pushup(id,m-l+1,r-m);
}
ll query()
{
return sum[1];
}
void build(int id,int l,int r,int num)
{
if (l==r)
{
suff[id]=pre[id]=sum[id]=cc[num][l];
return;
}
int m=(l+r)>>1;
build(lson,num);
build(rson,num);
pushup(id,m-l+1,r-m);
}
}sgt[17];

int main()
{
//    freopen("in.txt","r",stdin);
sumpre[0]=0;
sumpre[1]=1;
for (int i=2; i<=400000; i++)
sumpre[i]=sumpre[i-1]+i;

scanf("%d%d",&n,&m);
memset(cc,0,sizeof cc);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);

for (int i=0; i<up; i++)
{
sgt[i].init();
for (int j=1; j<=n; j++)
{
cc[i][j]=a[j]&(1<<i);
}
sgt[i].build(1,1,n,i);
}
int x,y;
while(m--)
{
scanf("%d%d",&x,&y);
memset(mc,0,sizeof mc);
int cnt=0;
while(y)
{
mc[cnt++]=y&1;
y>>=1;
}
for (int i=0; i<up; i++)
sgt[i].modify(x,mc[i],1,1,n);
ll ans=0;
for (int i=up-1; i>=0; i--)
{
ans<<=1LL;
ans+=sgt[i].query();
//            cout<<sgt[i].query()<<endl;
}
//        printf("%I64d\n",ans);
cout<<ans<<endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: