spoj GSS线段树以及二维树状数组合集

T1 维护lmax 向左延伸的最大值,rmax同理,sum区间和,ans答案。

转移见operator +

#include<bits/stdc++.h>
#define mid (l+(r-l)/2)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define int long long
using namespace std;
const int N =(int)1e5+10;
struct TREE {
	int lef,rig,sum,ans;
	int l,r;
	void clear() {lef=rig=sum=ans=0;}
	void debug() {
		printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans);
	}

}tr[N<<2];
int a[N];
TREE operator + (TREE l,TREE r) {
	TREE rt;rt.clear();
	rt.l=l.l;rt.r=r.r;
	rt.lef=max(l.sum+r.lef,l.lef);
	rt.rig=max(r.sum+l.rig,r.rig);
	rt.sum=l.sum+r.sum;
	rt.ans=max(l.ans,max(l.rig+r.lef,r.ans));
	return rt;
}

void build(int l,int r,int rt) {
	tr[rt].l=l,tr[rt].r=r;
	if(l==r) {
		tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l];
		return ;
	}
	build(l,mid,ls),build(mid+1,r,rs);
	tr[rt]=tr[ls]+tr[rs];
}

TREE query(int l,int r,int rt,int L,int R) {
	if(L==l&&r==R) {
		return tr[rt];
	}
	if(R<=mid) return query(l,mid,ls,L,R);
	else if(L>mid) return query(mid+1,r,rs,L,R);
	else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R);
}

int n,m;
main() {
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,n,1);
	cin>>m;
	for(int i=1;i<=m;i++) {
		int l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",query(1,n,1,l,r).ans);
	}
	return 0;
}

T2.维护区间去重之后最大值。

同多校2017#404记录前一个状态,然后一个一个加入,维护一个后缀和

#include<bits/stdc++.h>
#define int long long
#define mid (l+(r-l)/2)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define hash H_sh
using namespace std;
const int N =(int)2e5+10;
struct TREE {
	int max,lazy,pre_max,pre_lazy;
	int l,r;
	TREE() {max=lazy=pre_lazy=pre_max=0;}
}tr[N<<2];
int a[N];

struct QUERY {
	int l,r,id;
	bool operator <(const QUERY &rhs) const {
		return r<rhs.r;
	}
}p[N];
int n,m,ans[N],pre[N];

void pushup(int rt) {
	tr[rt].max=max(tr[ls].max,tr[rs].max);
	tr[rt].pre_max=max(tr[ls].pre_max,tr[rs].pre_max);
}

void pushdown(int rt) {//×¢ÒâÕâ¸öµÄpushdownµÄÕæÕýµÄÒâÒ壬ÊÇÏ´«±ê¼Ç£¬Ï´«¡£
	if(!(tr[rt].lazy|tr[rt].pre_lazy)) return ;
	tr[ls].pre_lazy=max(tr[ls].pre_lazy,tr[ls].lazy+tr[rt].pre_lazy);
	tr[rs].pre_lazy=max(tr[rs].pre_lazy,tr[rs].lazy+tr[rt].pre_lazy);
	tr[ls].pre_max=max(tr[ls].pre_max,tr[ls].max+tr[rt].pre_lazy);
	tr[rs].pre_max=max(tr[rs].pre_max,tr[rs].max+tr[rt].pre_lazy);
	tr[ls].lazy+=tr[rt].lazy,tr[rs].lazy+=tr[rt].lazy;
	tr[ls].max+=tr[rt].lazy,tr[rs].max+=tr[rt].lazy;
	tr[rt].lazy=tr[rt].pre_lazy=0;
}

void update(int l,int r,int rt,int L,int R,int C) {
	tr[rt].l=l,tr[rt].r=r;
	if(L==l&&r==R) {
		tr[rt].max+=C;tr[rt].lazy+=C;
		tr[rt].pre_max=max(tr[rt].pre_max,tr[rt].max);
		tr[rt].pre_lazy=max(tr[rt].pre_lazy,tr[rt].lazy);
		return ;
	}
	pushdown(rt);
	if(R<=mid) update(l,mid,ls,L,R,C);
	else if(L>mid) update(mid+1,r,rs,L,R,C);
	else update(l,mid,ls,L,mid,C),update(mid+1,r,rs,mid+1,R,C);
	pushup(rt);
}

int query(int l,int r,int rt,int L,int R) {
	if(l==L&&R==r) return tr[rt].pre_max;
	pushdown(rt);
	if(R<=mid) return query(l,mid,ls,L,R);
	else if(L>mid) return query(mid+1,r,rs,L,R);
	else return max(query(l,mid,ls,L,mid),query(mid+1,r,rs,mid+1,R));
}
int hash(int a) {return a+(int)1e5;}

main() {
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	cin>>m;
	for(int i=1;i<=m;i++)
		scanf("%lld%lld",&p[i].l,&p[i].r),p[i].id=i;
	sort(p+1,p+m+1);
	for(int i=1,pos=1;i<=n;i++) {
		update(1,n,1,pre[hash(a[i])]+1,i,a[i]);
		pre[hash(a[i])]=i;
		while(pos<=m&&p[pos].r==i)
			ans[p[pos].id]=query(1,n,1,p[pos].l,p[pos].r),pos++;
		if(pos>m) break;
	}
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}

T3.同t1多了一个修改

#include<bits/stdc++.h>
#define mid (l+(r-l)/2)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define int long long
using namespace std;
const int N =(int)1e5+10;
struct TREE {
	int lef,rig,sum,ans;
	int l,r;
	void clear() {lef=rig=sum=ans=0;}
	void debug() {
		printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans);
	}

}tr[N<<2];
int a[N];
TREE operator + (TREE l,TREE r) {
	TREE rt;rt.clear();
	rt.l=l.l;rt.r=r.r;
	rt.lef=max(l.sum+r.lef,l.lef);
	rt.rig=max(r.sum+l.rig,r.rig);
	rt.sum=l.sum+r.sum;
	rt.ans=max(l.ans,max(l.rig+r.lef,r.ans));
	return rt;
}

void build(int l,int r,int rt) {
	tr[rt].l=l,tr[rt].r=r;
	if(l==r) {
		tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l];
		return ;
	}
	build(l,mid,ls),build(mid+1,r,rs);
	tr[rt]=tr[ls]+tr[rs];
}

TREE query(int l,int r,int rt,int L,int R) {
	if(L==l&&r==R)  return tr[rt];
	if(R<=mid) return query(l,mid,ls,L,R);
	else if(L>mid) return query(mid+1,r,rs,L,R);
	else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R);
}

void update(int l,int r,int rt,int L,int C) {
	if(l==r) {tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=C;return ;}
	if(L<=mid)update(l,mid,ls,L,C);
	else update(mid+1,r,rs,L,C);
	tr[rt]=tr[ls]+tr[rs];
}

int n,m;
main() {
	cin>>n;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,n,1);
	cin>>m;
	for(int i=1;i<=m;i++) {
		int f,l,r;
		scanf("%lld%lld%lld",&f,&l,&r);
		if(f) printf("%lld\n",query(1,n,1,l,r).ans);
		else update(1,n,1,l,r);
	}
	return 0;
}

T4.区间开方求和,由于发现sqrt(1e18)嵌套6重向下取整为1,于是用线段树记录2一个区间还要不要暴力修改,需要的话暴力sqrt就行了。

#include<bits/stdc++.h>
#define int long long
#define cls(a) memset(a,0,sizeof(a))
#define mid (l+(r-l)/2)
#define ls (rt<<1)
#define rs (rt<<1|1)
using namespace std;
const int N =(int)1e6+10;
int sum[N],n,m,a[N],L[N],R[N];
void build(int l,int r,int rt) {
	L[rt]=l,R[rt]=r;
	if(l==r) {sum[rt]=a[l];return;}
	build(l,mid,ls),build(mid+1,r,rs);
	sum[rt]=sum[ls]+sum[rs];
}

void update(int l,int r,int rt,int L,int R) {
//	cout<<l<<" "<<r<<" "<<L<<" "<<R<<"\n";
	if(r-l+1==sum[rt]) return ;
	if(l==r) {sum[rt]=(int)sqrt(sum[rt]+0.0);return ;}//Ò»¶¨ÒªÊÇÒ¶×Ó½Úµã
	if(R<=mid) update(l,mid,ls,L,R);
	else if(L>mid) update(mid+1,r,rs,L,R);
	else update(l,mid,ls,L,mid),update(mid+1,r,rs,mid+1,R);
	sum[rt]=sum[ls]+sum[rs];
}

int query(int l,int r,int rt,int L,int R) {
	if(l==L&&r==R) return sum[rt];
	if(R<=mid) return query(l,mid,ls,L,R);
	else if(L>mid) return query(mid+1,r,rs,L,R);
	else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R);
}
void init() {
	cls(sum);
}

void debug(int l,int r,int rt) {
	if(l==r) {printf("%lld ",sum[rt]);return;}
	debug(l,mid,ls),debug(mid+1,r,rs);
//	sum[rt]=sum[ls]+sum[rs];
}

main() {
	int kase=0;
	while(cin>>n) {
		init();
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		build(1,n,1);
//		for(int i=1;i<=20;i++)
//			if(L[i])
//				printf("%d %d %d \n",L[i],R[i],sum[i]);
		cin>>m;printf("Case #%lld:\n",++kase);
		for(int i=1;i<=m;i++) {
			int f,l,r;
			scanf("%lld%lld%lld",&f,&l,&r);
			if(l>r) swap(l,r);
			if(!f) update(1,n,1,l,r);
			else printf("%lld\n",query(1,n,1,l,r));
//			debug(1,n,1);
		}
		puts("");
	}
	return 0;
}

分块也是一样的道理。记录一个块要不要sqrt

#include<bits/stdc++.h>
#define maxn 400000
#define int long long
#define cls(a) memset(a,0,sizeof(a))
using namespace std;

int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c==‘-‘) f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();}
	return x*f;
}
int v[maxn],atag[maxn],bl[maxn],n,blo,sum[maxn],m,flag[maxn];

void solve(int x)
{
	if(flag[x]) return;
	flag[x]=1;
	sum[x]=0;
	for(int i=(x-1)*blo+1;i<=x*blo;i++)
	{
		v[i]=sqrt(v[i]),sum[x]+=v[i];
		if(v[i]>1) flag[x]=0;
	}
}

void update(int a,int b)
{
	for(int i=a;i<=min(bl[a]*blo,b);i++)
		sum[bl[a]]-=v[i],v[i]=sqrt(v[i]),sum[bl[a]]+=v[i];
	if(bl[a]!=bl[b])
	{
		for(int i=(bl[b]-1)*blo+1;i<=b;i++)
			sum[bl[b]]-=v[i],v[i]=sqrt(v[i]),sum[bl[b]]+=v[i];
	}
	for(int i=bl[a]+1;i<=bl[b]-1;i++)
		solve(i);
}

int query(int a,int b)
{
	int ans=0;
	for(int i=a;i<=min(bl[a]*blo,b);i++)
		ans+=v[i];
	if(bl[a]!=bl[b])
	{
		for(int i=(bl[b]-1)*blo+1;i<=b;i++)
			ans+=v[i];
	}
	for(int i=bl[a]+1;i<=bl[b]-1;i++)
		ans+=sum[i];
	return ans;
}

main()
{
//	freopen("1012.out","r",stdin);
//  freopen("1.txt","w",stdout);
	int kase=0;
	while(~scanf("%lld",&n)&&n) {
		printf("Case #%lld:\n",++kase);
    	cls(v),cls(sum),cls(flag);cls(atag);cls(bl);
		blo=sqrt(n);
	    for(int i=1;i<=n;i++)
	    	v[i]=read(),bl[i]=(i-1)/blo+1,
	    	sum[bl[i]]+=v[i];
		m=read();
	    for(int i=1;i<=m;i++)
	    {
			int f=read(),a=read(),b=read();
                        if(a>b) swap(a,b);
			if(f==0)	update(a,b);
			else printf("%lld\n",query(a,b));
		}
		puts("");
	}
	return 0;
}

小坑,由于题目说的是x~y所以可能x>y需要swap一下。

T5.给定l,r的取值范围,求l~r和最大

分类讨论,具体见main函数。

小细节注意

要保证点在区间中,这个区间的完整性很重要,要注意如果选lmax那么就是至少选一个元素。

#include<bits/stdc++.h>
#define mid (l+(r-l)/2)
#define ls (rt<<1)
#define rs (rt<<1|1)
//#define int long long
#define root 1,n,1
using namespace std;
const int N =(int)1e5+10;
struct TREE {
	int lef,rig,sum,ans;
	int l,r;
	void clear() {lef=rig=sum=ans=0;}
	void debug() {
		printf("%d %d %d %d %d %d\n",l,r,lef,rig,sum,ans);
	}

}tr[N<<2],paste;
int a[N],t;
TREE operator + (TREE l,TREE r) {
	TREE rt;rt.clear();
	rt.l=l.l;rt.r=r.r;
	rt.lef=max(l.sum+r.lef,l.lef);
	rt.rig=max(r.sum+l.rig,r.rig);
	rt.sum=l.sum+r.sum;
	rt.ans=max(l.ans,max(l.rig+r.lef,r.ans));
	return rt;
}

void build(int l,int r,int rt) {
	tr[rt].l=l,tr[rt].r=r;
	if(l==r) {
		tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=a[l];
		return ;
	}
	build(l,mid,ls),build(mid+1,r,rs);
	tr[rt]=tr[ls]+tr[rs];
}

TREE query(int l,int r,int rt,int L,int R) {
	if(L>R) return paste;
	if(L==l&&r==R)  return tr[rt];
	if(R<=mid) return query(l,mid,ls,L,R);
	else if(L>mid) return query(mid+1,r,rs,L,R);
	else return query(l,mid,ls,L,mid)+query(mid+1,r,rs,mid+1,R);
}

void update(int l,int r,int rt,int L,int C) {
	if(l==r) {tr[rt].lef=tr[rt].rig=tr[rt].ans=tr[rt].sum=C;return ;}
	if(L<=mid)update(l,mid,ls,L,C);
	else update(mid+1,r,rs,L,C);
	tr[rt]=tr[ls]+tr[rs];
}

int n,m;
main() {
	paste.clear();cin>>t;
	for(;t;t--) {
		cin>>n;
		memset(tr,0,sizeof(tr));memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		build(root);
		cin>>m;
		for(int i=1;i<=m;i++) {
			int x1,x2,y1,y2;
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			if(y1<x2) {
				printf("%d\n",query(root,x1,y1).rig+query(root,y1+1,x2-1).sum+query(root,x2,y2).lef);
			}
			else {
				int m1=query(root,x2,y1).ans;
				int m2=query(root,x2,y2).lef+query(root,x1,x2-1).rig;
				int m3=query(root,x1,y1).rig+query(root,y1+1,y2).lef;
//				cout<<query(root,x1,x2-1).rig<<" "<<query(root,y1+1,y2).lef<<"\n";
				printf("%d\n",max(max(m1,m2),m3));
			}
		}
	}

	return 0;
}

后面的3题好像是splay啊,还是不怎么会写,以后再说吧,先挖一个坑。

最后来一发二维树状数组poj2155具体可以看《浅谈信息学竞赛中的“0”和“1”》这篇论文很详细。

一个小小的下标搞了好久。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cassert>
#define lowbit(_x) (_x&(-_x))
using namespace std;
int n,m,x1,x2,y1,y2,t,fst=187415157;
int sum[1100][1100];
void U(int x,int y,int val) {
	for(int i=x;i<=n;i+=lowbit(i))
		for(int j=y;j<=n;j+=lowbit(j))
			sum[i][j]+=val;
}
int query(int x,int y) {
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
		for(int j=y;j;j-=lowbit(j))
			ans+=sum[i][j];
	return ans;
}
char s[20];
main() {
	cin>>t;
	for(;t;t--){
		if(!fst)puts("");fst=0;
		memset(sum,0,sizeof(sum));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++) {
			scanf("%s",s);
			if(s[0]==‘C‘) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),U(x1,y1,1),U(x1,y2+1,1),U(x2+1,y1,1),U(x2+1,y2+1,1);
			else scanf("%d%d",&x1,&y1),printf("%d\n",query(x1,y1)%2);
		}
	}
}
时间: 2024-10-11 17:51:16

spoj GSS线段树以及二维树状数组合集的相关文章

SPOJ 1029 Matrix Summation【 二维树状数组 】

题意:二维树状数组,更改值的时候有一点不一样, 是将a[x][y]设置为一个值,所以add的时候要将它和以前的值作差一下 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set>

POJ 2029 Get Many Persimmon Trees (二维树状数组 or DP)

题意:一个H * W的大矩形,里面的某些格子种有树.现在要你找出一个h * w的小矩形,使得里面树的数量最多,问最多有多少棵树 是二维树状数组基础用法,边输入边更新有树的点,建完树后就可以查询每个(1,1)到(x,y)为对顶点的矩形中共有多少棵柿子树. 算法复杂度 O(H*W*lgH*lgW) 但是由于这题的柿子树一旦确定位置后就没有更新位置,所以不需要用树状数组也可,直接用dp统计每个(1,1)到(x,y)为对顶点的矩形中共有多少棵柿子树. 统计的状态转移方程是: for(int i=1;i<

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

hdu 2795 线段树(二维问题一维化)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10961    Accepted Submission(s): 4863 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

二维树状数组(水题) POJ1195

前段时间遇到线段树过不了,树状数组却过了的题.(其实线段树过得了的) 回忆了下树状数组. 主要原理,还是二进制位数,每一项的和表示其为它的前((最后一位1及其后)的二进制数)和,可从二进制图来看.(用线段树想一想其实只是线段树编号不同而已,本质类似) 写了下二维树状数组,几乎和一维相同,也没必要不同. #include <cstdio> #include <cstring> int l,r,x,y,n,a,p,sum[1125][1125]; inline int lowbit(i

[poj2155]Matrix(二维树状数组)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 25004   Accepted: 9261 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ1195 Mobile phones 二维树状数组的应用

这题可以用线段树离散化做,用二维树状数组做了一下,不懂得可以看一下这篇文章:http://www.java3z.com/cwbwebhome/article/article1/1369.html?id=4804 题意: 给你一个s*s的正方形区域,先输入一个x,若x==0,则再输入一个s,若x==1,则输入x,y,a,表示矩阵中(x,y)这点的值加上a,若x==2,输入l,b,r,t,代表以左上角的点(l,b)右下角的点(r,t),求这一片矩形内的矩阵元素之和,若x==3则结束此次程序 就是最基

poj 1195:Mobile phones(二维树状数组,矩阵求和)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The