///定义:
/*
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,
每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在
若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实
际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。
*/
/*
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,
每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在
若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实
际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。
*/
///代码:
/*
**name:一维线段树
**function:一维线段树的最值、区间和,区间更新
*/
#include <bits/stdc++.h>
#define MAXN 100010
#define inf 0x3f3f3f3f
using namespace std;
struct node{
int l,r;//区间[l,r]
int add;//区间的延时标记
int sum;//区间和
int mx; //区间最大值
int mn; //区间最小值
}tree[MAXN<<2];//一定要开到4倍多的空间
void pushup(int index){
tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum;
tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx);
tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);
}
void pushdown(int index){
//说明该区间之前更新过
//要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新
if(tree[index].add > 0){
//替换原来的值
tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add;
tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add;
tree[index<<1].mx += tree[index].add;
tree[index<<1|1].mx += tree[index].add;
tree[index<<1].mn += tree[index].add;
tree[index<<1|1].mn += tree[index].add;
tree[index<<1].add += tree[index].add;
tree[index<<1|1].add += tree[index].add;
tree[index].add = 0;
}
}
void build(int l,int r,int index){
tree[index].l = l;
tree[index].r = r;
tree[index].add = 0;//刚开始一定要清0
if(l == r){
scanf("%d",&tree[index].sum);
tree[index].mn = tree[index].mx = tree[index].sum;
return ;
}
int mid = (l+r)>>1;
build(l,mid,index<<1);
build(mid+1,r,index<<1|1);
pushup(index);
}
void updata(int l,int r,int index,int val){
if(l <= tree[index].l && r >= tree[index].r){
/*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1
个数,所以区间和 以及 最值为:
*/
/*tree[index].sum = (tree[index].r-tree[index].l+1)*val;
tree[index].mn = val;
tree[index].mx = val;
tree[index].add = val;//延时标记*/
//在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1
//个数,所以区间和 以及 最值为:
tree[index].sum += (tree[index].r-tree[index].l+1)*val;
tree[index].mn += val;
tree[index].mx += val;
tree[index].add += val;//延时标记
return ;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)>>1;
if(l <= mid){
updata(l,r,index<<1,val);
}
if(r > mid){
updata(l,r,index<<1|1,val);
}
pushup(index);
}
int query(int l,int r,int index){
if(l <= tree[index].l && r >= tree[index].r){
//return tree[index].sum;
return tree[index].mx;
//return tree[index].mn;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)>>1;
int ans = 0;
int Max = 0;
int Min = inf;
if(l <= mid){
ans += query(l,r,index<<1);
Max = max(query(l,r,index<<1),Max);
Min = min(query(l,r,index<<1),Min);
}
if(r > mid){
ans += query(l,r,index<<1|1);
Max = max(query(l,r,index<<1|1),Max);
Min = min(query(l,r,index<<1|1),Min);
}
//return ans;
return Max;
//return Min;
}
int main()
{
int n,m,q,x,y,z;
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
while(m--){
scanf("%d",&q);
if(q == 1){
cout<<"查询:(x,y)"<<endl;
scanf("%d %d",&x,&y);
cout<<query(x,y,1)<<endl;
}
else{
cout<<"更新(x,y)为z:"<<endl;
scanf("%d %d %d",&x,&y,&z);
updata(x,y,1,z);
for(int i = 1; i <= n; ++i){
printf("a[%d] = %d\n",i,query(i,i,1));
}
}
}
}
return 0;
}
/*
**name:一维线段树
**function:一维线段树的区间翻转
**题意:给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列
。用线段树维护区间更改。线段树的叶子节点存每个位置是原序列中的第几号元素。
然后维护当前点的编号和每个点的左右儿子的序号,反转区间时,交换左右儿子即可,不过要注意,
每次打标记的时候,不能直接把delta置1(防止覆盖原标记),用异或取反
*/
///(注意,这样做是有BUG的,只有在交换区间正好是线段树中的整区间才行。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int tree[6000010][3],delta[6000010];
int n,m,a[150010],num[150010];
inline void swap(int now)
{
int t;
t=tree[now][1];
tree[now][1]=tree[now][2];
tree[now][2]=t;
}
inline void updata(int now)
{
tree[now][0]=0;
tree[now][1]=(now<<1);
tree[now][2]=(now<<1)|1;
}
inline void pushdown(int now)
{
if(delta[now])
{
swap(now<<1);
swap(now<<1|1);
delta[now<<1]^=1;
delta[now<<1|1]^=1;
delta[now]=0;
}
}
void build(int now,int l,int r)
{
if(l==r)
{
tree[now][0]=l;
return;
}
int mid=(l+r)>>1;
build((now<<1),l,mid);
build((now<<1)|1,mid+1,r);
updata(now);
}
void change(int now,int l,int r,int al,int ar)
{
if(al<=l&&r<=ar)
{
swap(now);
delta[now]^=1;
return;
}
int mid=(l+r)>>1;
pushdown(now);
if(al<=mid) change(tree[now][1],l,mid,al,ar);
if(ar>mid) change(tree[now][2],mid+1,r,al,ar);
}
int ask(int now,int l,int r,int al,int ar)
{
if(al<=l&&r<=ar) return tree[now][0];
int mid=(l+r)>>1;
pushdown(now);
if(al<=mid) return ask(tree[now][1],l,mid,al,ar);
if(ar>mid) return ask(tree[now][2],mid+1,r,al,ar);
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1; i<=n; ++i) scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
for(i=1; i<=m; ++i)
{
int x,y;
scanf("%d%d",&x,&y);
change(1,1,n,x,y);
}
for(j=1; j<=n; ++j) num[j]=ask(1,1,n,j,j);
for(j=1; j<=n; ++j) printf("%d ",a[num[j]]);
return 0;
}
/*
**name:二维线段树
**function:二维线段树区间翻转
**题意:有一个矩阵,初始全是0,然后对区间左上角(x1,y1)-右下角(y1,y2)翻转
0变成1,1变成0,然后查询点(x,y)的值
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
bool a[1005<<2][1005<<2];///二维线段树
int n;
void upy(int root,int rt,int l,int r,int y1,int y2)
{
if(y1<=l&&r<=y2)
{
a[root][rt]=!a[root][rt];///找到合适的区间进行翻转
return ;
}
int mid=(l+r)>>1;
if(y1<=mid)upy(root,rt<<1,l,mid,y1,y2);///按y更新
if(y2>mid) upy(root,rt<<1|1,mid+1,r,y1,y2);
}
void upx(int rt,int l,int r,int x1,int x2,int y1,int y2)
{
if(x1<=l&&r<=x2)///先找出一维x
{
upy(rt,1,1,n,y1,y2);///在rt这个节点上在建y的线段树
return ;
}
int mid=(l+r)>>1;
if(x1<=mid)upx(rt<<1,l,mid,x1,x2,y1,y2);///按x更新
if(x2>mid) upx(rt<<1|1,mid+1,r,x1,x2,y1,y2);
}
long long sum;
void qy(int root,int rt,int l,int r,int y)
{
if(a[root][rt])sum++;///在x的root和y的rt这个区间上,
///如果是1就++,因为初始值为0,看翻转的次数
if(l==r)return ;
int mid=(l+r)>>1;///结束条件
if(y<=mid)qy(root,rt<<1,l,mid,y);///根据y查找
if(y>mid)qy(root,rt<<1|1,mid+1,r,y);
}
void qx(int rt,int l,int r,int x,int y)
{
qy(rt,1,1,n,y);///在rt这个点上查询y
if(l==r)return ;///递归结束条件
int mid=(l+r)>>1;
if(x<=mid)qx(rt<<1,l,mid,x,y);///查找x的位置
if(x>mid)qx(rt<<1|1,mid+1,r,x,y);
}
int main()
{
int t;
cin>>t;
while(t--)
{
int T;
char ch[5];
int x,y,x1,x2,y1,y2;
cin>>n>>T;
memset(a,0,sizeof(a));
while(T--)
{
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);///输入更新的区间点
upx(1,1,n,x1,x2,y1,y2);///更新线段树
}
else
{
scanf("%d%d",&x,&y);
sum=0;
qx(1,1,n,x,y);///在线段树中查询
if(sum%2)printf("1\n");///看(x,y)的所有父节点一共翻转了几次
else printf("0\n");
}
}
printf("\n");
}
return 0;
}
/* **name:二维线段树求最大值和最小值 **来源:HDU4819 */ # include<cstdio> # include<cstring> # include<algorithm> using namespace std; # define lson l,m,rt<<1 # define rson m+1,r,rt<<1|1 # define MAXN 805 int xL,xR,yL,yR,val; int maxv,minv; int Max[MAXN<<2][MAXN<<2],Min[MAXN<<2][MAXN<<2]; int N,mat[MAXN][MAXN]; void PushUp(int xrt,int rt) { Max[xrt][rt]=max(Max[xrt][rt<<1],Max[xrt][rt<<1|1]); Min[xrt][rt]=min(Min[xrt][rt<<1],Min[xrt][rt<<1|1]); } void BuildY(int xrt,int x,int l,int r,int rt) { int m; if(l==r) { if(x!=-1) Max[xrt][rt]=Min[xrt][rt]=mat[x][l]; else { Max[xrt][rt]=max(Max[xrt<<1][rt],Max[xrt<<1|1][rt]); Min[xrt][rt]=min(Min[xrt<<1][rt],Min[xrt<<1|1][rt]); } return; } m=(l+r)>>1; BuildY(xrt,x,lson); BuildY(xrt,x,rson); PushUp(xrt,rt); } void BuildX(int l,int r,int rt) { int m; if(l==r) { BuildY(rt,l,1,N,1); return; } m=(l+r)>>1; BuildX(lson); BuildX(rson); BuildY(rt,-1,1,N,1); } void UpdateY(int xrt,int x,int l,int r,int rt) { int m; if(l==r) { if(x!=-1) Max[xrt][rt]=Min[xrt][rt]=val; else { Max[xrt][rt]=max(Max[xrt<<1][rt],Max[xrt<<1|1][rt]); Min[xrt][rt]=min(Min[xrt<<1][rt],Min[xrt<<1|1][rt]); } return; } m=(l+r)>>1; if(yL<=m) UpdateY(xrt,x,lson); else UpdateY(xrt,x,rson); PushUp(xrt,rt); } void UpdateX(int l,int r,int rt) { int m; if(l==r) { UpdateY(rt,l,1,N,1); return; } m=(l+r)>>1; if(xL<=m) UpdateX(lson); else UpdateX(rson); UpdateY(rt,-1,1,N,1); } void QueryY(int xrt,int l,int r,int rt) { int m; if(yL<=l&&yR>=r) { minv=min(minv,Min[xrt][rt]); maxv=max(maxv,Max[xrt][rt]); return; } m=(l+r)>>1; if(yL<=m) QueryY(xrt,lson); if(yR>m) QueryY(xrt, rson); } void QueryX(int l,int r,int rt) { int m; if(xL<=l&&xR>=r) { QueryY(rt,1,N,1); return; } m=(l+r)>>1; if(xL<=m) QueryX(lson); if(xR>m) QueryX(rson); } int main() { //freopen("in.txt","r",stdin); int i,j,q,cas,T,x,y,l; char op[5]; scanf("%d",&T); for(cas=1;cas<=T;cas++) { scanf("%d",&N); for(i=1;i<=N;i++) for(j=1;j<=N;j++) scanf("%d",&mat[i][j]); BuildX(1,N,1); scanf("%d",&q); printf("Case #%d:\n",cas); while(q--) { scanf("%d%d%d",&x,&y,&l); l=(l+1)/2; xL=max(1,x-l+1),xR=min(N,x+l-1); yL=max(1,y-l+1),yR=min(N,y+l-1); minv=1<<30,maxv=-(1<<30); QueryX(1,N,1); val=(maxv+minv)/2; xL=x,yL=y; printf("%d\n",val); UpdateX(1,N,1); } } return 0; }
/* **name:二维线段树 **function:二维线段树求区间和 **题意: 一个矩阵,初始化为0,两种操作: 1、将某点增加val 2、查询一个子矩阵的和 **思路: 二维线段树,单点更新,区间求和,记得pushup. */ #include<stdio.h> #include<string.h> #include<stdlib.h> #define N 1050 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r int sum[N*3][N*3]; int n; void SubBuild(int rt,int l,int r,int t) { sum[t][rt] = 0; if(l!=r) { int mid = (l + r) >> 1; SubBuild(lson,t); SubBuild(rson,t); } } void Build(int rt,int l,int r) { SubBuild(1,1,n,rt); if(l!=r) { int mid = (l + r) >> 1; Build(lson); Build(rson); } } void SubUpdate(int rt,int l,int r,int y,int val,int t) { if(l == r) sum[t][rt] += val; else { int mid = (l + r) >> 1; if(y <= mid) SubUpdate(lson,y,val,t); else SubUpdate(rson,y,val,t); sum[t][rt] = sum[t][rt<<1] + sum[t][rt<<1|1]; } } void Update(int rt,int l,int r,int x,int y,int val) { SubUpdate(1,1,n,y,val,rt); if(l!=r) { int mid = (l + r) >> 1; if(x <= mid) Update(lson,x,y,val); else Update(rson,x,y,val); } } __int64 SubQuery(int rt,int l,int r,int LY,int RY,int t) { if(LY <= l && RY >= r) return sum[t][rt]; int mid = (l + r) >> 1; __int64 ans = 0; if(LY <= mid) ans += SubQuery(lson,LY,RY,t); if(RY > mid ) ans += SubQuery(rson,LY,RY,t); return ans; } __int64 Query(int rt,int l,int r,int LX,int RX,int LY,int RY) { if(LX <= l && RX >= r) { return SubQuery(1,1,n,LY,RY,rt); } int mid = (l + r) >> 1; __int64 ans = 0; if(LX <= mid) ans += Query(lson,LX,RX,LY,RY); if(RX > mid ) ans += Query(rson,LX,RX,LY,RY); return ans; } int main() { int op; int a,b,c,d; while(scanf("%d %d",&op,&n)!=EOF) { ++n; Build(1,1,n); while(scanf("%d",&op)) { if(op == 3) break; if(op == 1) { scanf("%d %d %d",&a,&b,&c); ++a,++b; Update(1,1,n,a,b,c); } else { scanf("%d %d %d %d",&a,&b,&c,&d); ++a,++b,++c,++d; printf("%I64d\n",Query(1,1,n,a,c,b,d)); } } } return 0; }