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位所有的权值和,按二进制组合一下就是最后的答案..
首先要确定一点,连续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; }
相关文章推荐
- CodeForces - 400E(模拟+线段树或暴力)
- Codeforces400E - Inna and Binary Logic - 思维、数学
- [扫描线 线段树] Codeforces 720D Russian Code Cup 2016 - Finals D. Slalom
- CodeForces 240F TorCoder(线段树)
- Codeforces 842 D Vitya and Strange Lesson 线段树 (未理解透)
- CodeForces - 668D Little Artem and Time Machine(线段树||树状数组)
- CodeForces 19D Points (线段树+set)
- Codeforces 799C Fountains【思维+分类讨论+线段树】
- [Codeforces 893F. Subtree Minimum Query]线段树合并
- Codeforces 85B. Embassy Queue【线段树、贪心】
- Codeforces 240F. TorCoder 线段树
- CodeForces 296C Greg and Array (线段树)
- Codeforces 482B Interesting Array(线段树)
- Codeforces 400E Inna and Binary Logic(位运算+暴力)
- CodeForces - 652D(线段树+离散化)
- [线段树]CodeForces 356A
- Codeforces 626G Raffles 【贪心】【线段树】
- codeforces 91B Queue 线段树,简单查询
- Codeforces 627B Factory Repairs 线段树
- 【线段树】 codeforces 444C DZY Loves Colors