【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和

题意:给出N个数,M个操作。操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和。n,m<=100000,ai<=1000

题解:

当年(其实也就是今年)做不出来的题。。D1T1啊。。。

因为ai<=1000,我们可以拆位处理。拆成10个二进制位,每位开1棵线段树。

对于每个节点,维护:

d:这段区间的异或和

L[0],L[1]:子区间一定从左端点开始,异或和为0,1的子区间分别有多少个

R[0],R[1]:子区间一定从右端点开始,异或和为0,1的子区间分别有多少个

s[0],s[1]:异或和为0,1的子区间分别有多少个

然后重点就是合并啦。

 1 node upd(int ind,int tmp,node lc,node rc)
 2 {
 3     int dl=lc.d,dr=rc.d;
 4     node x;
 5     if(tmp!=0) x=t[ind][tmp];
 6     x.d=lc.d^rc.d;
 7     x.L[0]=(lc.L[0]+rc.L[(dl==0) ? 0:1])%mod;
 8     x.L[1]=(lc.L[1]+rc.L[(dl==0) ? 1:0])%mod;
 9     x.R[0]=(rc.R[0]+lc.R[(dr==0) ? 0:1])%mod;
10     x.R[1]=(rc.R[1]+lc.R[(dr==0) ? 1:0])%mod;
11     x.s[0]=(lc.s[0]+rc.s[0]+(lc.R[0]*rc.L[0])%mod+(lc.R[1]*rc.L[1])%mod)%mod;
12     x.s[1]=(lc.s[1]+rc.s[1]+(lc.R[0]*rc.L[1])%mod+(lc.R[1]*rc.L[0])%mod)%mod;
13     return x;
14 }

我打成node形式。。因为最后查询的时候有多个区间也要合并。。

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8
  9 typedef long long LL;
 10 const int N=100010;
 11 const LL mod=100000007;
 12 struct node{
 13     int l,r,lc,rc,d;
 14     LL L[2],R[2],s[2];
 15     //L:从左开始
 16     //R:从右开始
 17     //s:总答案
 18 }t[10][2*N];
 19 char c[10];
 20 int n,m,tl,a[N][10];
 21 LL bit[15];
 22
 23 node upd(int ind,int tmp,node lc,node rc)
 24 {
 25     int dl=lc.d,dr=rc.d;
 26     node x;
 27     if(tmp!=0) x=t[ind][tmp];
 28     x.d=lc.d^rc.d;
 29     x.L[0]=(lc.L[0]+rc.L[(dl==0) ? 0:1])%mod;
 30     x.L[1]=(lc.L[1]+rc.L[(dl==0) ? 1:0])%mod;
 31     x.R[0]=(rc.R[0]+lc.R[(dr==0) ? 0:1])%mod;
 32     x.R[1]=(rc.R[1]+lc.R[(dr==0) ? 1:0])%mod;
 33     x.s[0]=(lc.s[0]+rc.s[0]+(lc.R[0]*rc.L[0])%mod+(lc.R[1]*rc.L[1])%mod)%mod;
 34     x.s[1]=(lc.s[1]+rc.s[1]+(lc.R[0]*rc.L[1])%mod+(lc.R[1]*rc.L[0])%mod)%mod;
 35     return x;
 36 }
 37
 38 int bt(int ind,int l,int r)
 39 {
 40     int x=++tl;
 41     t[ind][x].l=l;t[ind][x].r=r;
 42     t[ind][x].lc=t[ind][x].rc=0;
 43     t[ind][x].d=0;
 44     memset(t[ind][x].L,0,sizeof(t[ind][x].L));
 45     memset(t[ind][x].R,0,sizeof(t[ind][x].R));
 46     memset(t[ind][x].s,0,sizeof(t[ind][x].s));
 47     if(l<r)
 48     {
 49         int mid=(l+r)/2;
 50         t[ind][x].lc=bt(ind,l,mid);
 51         t[ind][x].rc=bt(ind,mid+1,r);
 52         int lc=t[ind][x].lc,rc=t[ind][x].rc;
 53         t[ind][x]=upd(ind,x,t[ind][lc],t[ind][rc]);
 54     }
 55     else
 56     {
 57         int d=a[l][ind];
 58         t[ind][x].d=d;
 59         t[ind][x].L[d]=t[ind][x].R[d]=t[ind][x].s[d]=1;
 60     }
 61     return x;
 62 }
 63
 64 void change(int ind,int x,int p,int d)
 65 {
 66     if(t[ind][x].l==t[ind][x].r)
 67     {
 68         t[ind][x].d=d;
 69         t[ind][x].L[d]=t[ind][x].R[d]=t[ind][x].s[d]=1;
 70         t[ind][x].L[d^1]=t[ind][x].R[d^1]=t[ind][x].s[d^1]=0;
 71         return ;
 72     }
 73     int lc=t[ind][x].lc,rc=t[ind][x].rc,mid=(t[ind][x].l+t[ind][x].r)/2;
 74     if(p<=mid) change(ind,lc,p,d);
 75     else change(ind,rc,p,d);
 76     t[ind][x]=upd(ind,x,t[ind][lc],t[ind][rc]);
 77 }
 78
 79 node query(int ind,int x,int l,int r)
 80 {
 81     if(t[ind][x].l==l && t[ind][x].r==r) return t[ind][x];
 82     int lc=t[ind][x].lc,rc=t[ind][x].rc,mid=(t[ind][x].l+t[ind][x].r)/2;
 83     if(r<=mid) return query(ind,lc,l,r);
 84     else if(l>mid) return query(ind,rc,l,r);
 85     else
 86     {
 87         node a0=query(ind,lc,l,mid);
 88         node a1=query(ind,rc,mid+1,r);
 89         return upd(0,0,a0,a1);
 90     }
 91 }
 92
 93 void output(int ind,int x)
 94 {
 95     int lc=t[ind][x].lc,rc=t[ind][x].rc;
 96     printf("l=%d r=%d d=%d l0=%lld l1=%lld r0=%lld r1=%lld s0=%lld s1=%lld\n",t[ind][x].l,t[ind][x].r,t[ind][x].d,t[ind][x].L[0],t[ind][x].L[1],t[ind][x].R[0],t[ind][x].R[1],t[ind][x].s[0],t[ind][x].s[1]);
 97     if(lc) output(ind,lc);
 98     if(rc) output(ind,rc);
 99 }
100
101 int main()
102 {
103     freopen("a.in","r",stdin);
104     freopen("me.out","w",stdout);
105     // freopen("cardcaptor.in","r",stdin);
106     // freopen("cardcaptor.out","w",stdout);
107     scanf("%d",&n);
108     int x,ind;node now;
109     bit[0]=1;
110     for(int i=1;i<=10;i++) bit[i]=bit[i-1]*2;
111     memset(a,0,sizeof(a));
112     for(int i=1;i<=n;i++)
113     {
114         scanf("%d",&x);
115         ind=0;
116         while(x)
117         {
118             a[i][ind]=x%2;
119             x/=2;
120             ind++;
121         }
122     }
123     scanf("%d",&m);
124     for(int i=0;i<10;i++) {tl=0;bt(i,1,n);}
125     for(int i=1;i<=m;i++)
126     {
127         scanf("%s",c);
128         if(c[0]==‘Q‘)
129         {
130             int l,r;LL ans=0;
131             scanf("%d%d",&l,&r);
132             for(int j=0;j<10;j++)
133             {
134                 now=query(j,1,l,r);
135                 ans=(ans+(bit[j]*now.s[1])%mod)%mod;
136             }
137             printf("%lld\n",ans);
138         }
139         else
140         {
141             int ind=0,p,d;
142             scanf("%d%d",&p,&d);
143             while(d)
144             {
145                 change(ind,1,p,d%2);
146                 d/=2;
147                 ind++;
148             }
149             for(int j=ind;j<10;j++) change(j,1,p,0);
150         }
151     }
152     return 0;
153 }
时间: 2024-10-07 01:19:28

【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和的相关文章

线段树维护区间开方/除法

今天考试考了一些神仙数据结构 T1 线段树维护区间加,区间开方,区间和 (数据范围:5e5) T2 线段树维护区间加,区间除,区间和,区间最值 对于这些题目,就像是之前考的区间与,区间或一样,除法,开方的操作会让各个数字之间越来越相近,最后变成一串一串连续的数字都是一样的,所以对于这一部分的操作我们一定程度上使用暴力,而如果一段都相等就相当于直接进行区间剪发的操作 那么我们来看如何判断区间一段都相等,那我们只需要维护区间的最值,最小值==最大值就完全相等了 然后.....代码.....被 \(y

线段树维护区间最大子段和

线段树:我还是很强的 简略讲解 要用线段树维护区间,我们要明确: 线段树存什么东西 怎么合并 如果有区间修改,怎么打标记 对于区间最大子段和,我们可以记录四个值:以维护的区间左端点为起点的最大子段和,以维护的区间右端点为终点的最大子段和,在维护区间内的最大子段和 和维护区间所有元素的和 合并的话稍微麻烦一些,看代码吧: inline void up(int p){ tree[p].sum=tree[ls].sum+tree[rs].sum; //维护区间总和 tree[p].ll=max(tre

最敏捷的机器人(线段树维护区间最值)

题面: Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了--机器人们都想知道谁是最敏捷的,于是它们进行了如下一个比赛.首先,他们面前会有一排共n个数,它们比赛看谁能最先把每连续k个数中最大和最小值写下来,当然,这些机器人运算速度都很,它们比赛的是谁写得快.但是Wind也想知道答案,你能帮助他吗? Input: 每组测试数据 第1行为n,k(1<=k<=n<=100000) 第2行共n个数,为数字序列,所有数字均在int范围内. Output: 共n-k+1行 第

线段树维护区间最大子段和 枚举 HDU6638

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6638 题意:在一个二维坐标系上给你n(n<=2000)个点,点带有一个价值w(有正有负),点的坐标都在(-1e9,1e9)的范围之间,可任意用一个平行于坐标轴的矩形框住一片区域,求这片区域框住的点的价值和 分析:点的坐标范围太大,离散化应能想到.离散化后可以考虑枚举左边界,枚举左边界后按照横坐标的依次加点(以一列一列为单位),用线段树维护一列的最大子段和,每移动到新的一列,继续加点时,等价于向原先的

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

HDU 2795 Billboard 【线段树维护区间最大值&amp;&amp;查询变形】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=2795 Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 28743    Accepted Submission(s): 11651 Problem Description At the entrance to the un

线段树维护区间合并——cf1285E

感觉自己的解法又是歪的 代码写的很乱..要先找出一开始有多少段,然后计算删掉每条线段的贡献,求个最大值就可以 删每条线段的贡献可以用线段树区间合并来做 ps:正解其实很简单..扫描一下就可以了 /* 先把所有线段覆盖到线段树上 然后对每一个线段[L,R],查询区间[L,R]有多少值>1的段即可 */ #include<bits/stdc++.h> using namespace std; #define N 800005 int n,x[N],L[N],R[N],tot; #define

hdu 4553 约会安排 (两个线段树维护区间)

include include include include include include include include define ll long long define FOR(i,l,r) for(int i = l ; i <= r ;++i ) define inf 1<<30 define EPS (1e-9) define lson(p) (p<<1) define rson(p) (p<<1|1) using namespace std;

HDU5692 dfs + 线段树维护区间最大值

先附上题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692 Problem Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化.小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次.另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机. 为小度熊规划一个路线,使得路线上的价值总和最