FZU 2105 Digits Count(线段树)
2015-08-23 20:56
489 查看
Problem 2105 Digits Count
Accept: 302 Submit: 1477
Time Limit: 10000 mSec Memory Limit : 262144 KB
Problem Description
Given N integers A={A[0],A[1],…,A[N-1]}. Here we have some operations:
Operation 1: AND opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] AND opn (here “AND” is bitwise operation).
Operation 2: OR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] OR opn (here “OR” is bitwise operation).
Operation 3: XOR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] XOR opn (here “XOR” is bitwise operation).
Operation 4: SUM L R
We want to know the result of A[L]+A[L+1]+…+A[R].
Now can you solve this easy problem?
Input
The first line of the input contains an integer T, indicating the number of test cases. (T≤100)
Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.
Then one line follows n integers A[0], A[1], …, A[n-1] (0≤A[i]<16,0≤in).
Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)
Output
For each test case and for each “SUM” operation, please output the result with a single line.
Sample Input
1
4 4
1 2 4 7
SUM 0 2
XOR 5 0 0
OR 6 0 3
SUM 0 2
Sample Output
7
18
Hint
A = [1 2 4 7]
SUM 0 2, result=1+2+4=7;
XOR 5 0 0, A=[4 2 4 7];
OR 6 0 3, A=[6 6 6 7];
SUM 0 2, result=6+6+6=18.
由于数据特别多,但是数据的值不大(<16),所以必有大量重复的元素就可以进行区间合并
Accept: 302 Submit: 1477
Time Limit: 10000 mSec Memory Limit : 262144 KB
Problem Description
Given N integers A={A[0],A[1],…,A[N-1]}. Here we have some operations:
Operation 1: AND opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] AND opn (here “AND” is bitwise operation).
Operation 2: OR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] OR opn (here “OR” is bitwise operation).
Operation 3: XOR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] XOR opn (here “XOR” is bitwise operation).
Operation 4: SUM L R
We want to know the result of A[L]+A[L+1]+…+A[R].
Now can you solve this easy problem?
Input
The first line of the input contains an integer T, indicating the number of test cases. (T≤100)
Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.
Then one line follows n integers A[0], A[1], …, A[n-1] (0≤A[i]<16,0≤in).
Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)
Output
For each test case and for each “SUM” operation, please output the result with a single line.
Sample Input
1
4 4
1 2 4 7
SUM 0 2
XOR 5 0 0
OR 6 0 3
SUM 0 2
Sample Output
7
18
Hint
A = [1 2 4 7]
SUM 0 2, result=1+2+4=7;
XOR 5 0 0, A=[4 2 4 7];
OR 6 0 3, A=[6 6 6 7];
SUM 0 2, result=6+6+6=18.
由于数据特别多,但是数据的值不大(<16),所以必有大量重复的元素就可以进行区间合并
#include <set> #include <map> #include <list> #include <stack> #include <cmath> #include <vector> #include <queue> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define PI cos(-1.0) #define RR freopen("input.txt","r",stdin) using namespace std; typedef long long LL; const int MAX = 1000010; int Seg[MAX*6]; int Arr[MAX]; int n,m; int Oper(int num,int PN,int OP)//进行操作 { switch(OP) { case 1: return num&PN; case 2: return num|PN; case 3: return num^PN; } return 0; } void Build(int L,int R,int site)//建立线段树 { if(L==R) { Seg[site]=Arr[L]; return ; } int mid=(L+R)>>1; Build(L,mid,site<<1); Build(mid+1,R,site<<1|1); if(Seg[site<<1]==Seg[site<<1|1]&&Seg[site<<1]!=1)//将值相同的区间进行合并,如果不相同则为-1. { Seg[site]=Seg[site<<1]; } else { Seg[site]=-1; } } void Update(int L,int R,int l,int r,int site,int PN,int OP)//更新操作 { if(L==l&&R==r&&Seg[site]!=-1)//三种操作 { Seg[site]=Oper(Seg[site],PN,OP); return ; } int mid = (L+R)>>1; if(Seg[site]!=-1)//向下更新,如过对已经合并的区间里面进行操作,则需要将区间先拆分,更行完以后再判断是否可以合并 { Seg[site<<1]=Seg[site<<1|1]=Seg[site]; Seg[site]=-1; } if(r<=mid) { Update(L,mid,l,r,site<<1,PN,OP); } else if(l>mid) { Update(mid+1,R,l,r,site<<1|1,PN,OP); } else { Update(L,mid,l,mid,site<<1,PN,OP); Update(mid+1,R,mid+1,r,site<<1|1,PN,OP); } if(Seg[site<<1]==Seg[site<<1|1]&&Seg[site<<1]!=1)//区间合并 { Seg[site]=Seg[site<<1]; } } int Query(int L,int R,int l,int r,int site)//查询 { if(L==l&&R==r&&Seg[site]!=-1) { return (R-L+1)*Seg[site]; } if(Seg[site]!=-1)//查询的时候,如果要查询一个区间内的区间,则需要先将区间向下更新(想想为什么?); { Seg[site<<1]=Seg[site<<1|1]=Seg[site]; Seg[site]=-1; } int mid=(L+R)>>1; if(r<=mid) { return Query(L,mid,l,r,site<<1); } else if(l>mid) { return Query(mid+1,R,l,r,site<<1|1); } else { return Query(L,mid,l,mid,site<<1)+Query(mid+1,R,mid+1,r,site<<1|1); } } int main() { int T; char str[15]; int l,r,PN; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { scanf("%d",&Arr[i]); } Build(0,n-1,1); for(int i=1;i<=m;i++) { scanf("%s",str); if(strcmp(str,"SUM")==0) { scanf("%d %d",&l,&r); printf("%d\n",Query(0,n-1,l,r,1)); } else { scanf("%d %d %d",&PN,&l,&r); if(strcmp(str,"AND")==0) { Update(0,n-1,l,r,1,PN,1); } else if(strcmp(str,"OR")==0) { Update(0,n-1,l,r,1,PN,2); } else if(strcmp(str,"XOR")==0) { Update(0,n-1,l,r,1,PN,3); } } } } return 0; }
相关文章推荐
- (2.1.21)IO流
- 读书笔记1-《万万没想到》
- A009-layout资源
- TCP/IP SOCKET HTTP及HTTPS之间的关系及各自特性之总结
- 王爽《汇编语言》第2版-----4、第一个程序
- Problem NYOJ-712 探寻宝藏 (双向DP)
- hdu 2975 Billboard
- 黑马程序员——27,正则表达式
- 一切从Markdown开始
- iOS项目开发实战——学会使用TableView列表控件(四)plist读取与Section显示
- 线性同余方程组模板
- 上楼梯问题的解法
- android 自定义对话框
- java中hex转byte问题
- Feel Good(单调栈(比之前更加完善的模板))
- 【java开发】方法重写和方法重载概述
- Hibernate缓存
- 深入浅出PHP(Exploring PHP)
- 编程学习笔记之D语言(一)
- Linux命令详解(2):pwd