[BZOJ1500]NOI2005 维修数列|splay

这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛。。一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了。。然后想了很久突然顿悟。。貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛。。(当时太弱)

然后我就一口气写了下来。。

对每个节点维护size,sum,maxsum,maxpre,maxpos(这两个用于更新maxsum),same,rev(这两个是lazy标记)。

更新maxsum考虑3种情况,一是左儿子的maxsum,二是右儿子的maxsum,三是左儿子的maxpos+自身num+右儿子maxpre,这里maxpre和maxpos更新的时候是可以一个都不要也就是为0的,我就在这里被坑了。。

1.      初始或者插入的时候建树用类似线段树的二分的方法,然后把pos转到root,把pos+1转到root下,只要把数挂在pos+1的左儿子下就行了。。这里有一个关于findkth的问题,为了方便处理边界我一开始插入了一个头结点和一个尾结点,findkth的时候要小心头结点的存在。。

2.      删除的时候把pos转到root,pos+tot+1转到root下,pos+tot+1的左儿子就是要删除的区间,直接删去即可。。这里要注意一个回收内存的问题,要把删去的结点放到一个栈里,newnode的时候优先从这个栈里拿结点,这样既可以节省内存又可以节省时间。。

3.      修改和翻转的时候找出区间打上标记就行。

4.      getsum找出区间直接输出答案,maxsum直接输出root的答案。

打到这里最原始的程序就写完了,但是我一开始在处理标记的时候只是单纯的打上标记没有更新维护的东西,导致每次输出答案必须遍历子树更新答案,时间复杂度没有了保证。。然后我看黄学长的代码发现打标记的时候要把信息及时维护一下,一加上去速度瞬间就快了起来。。(当时太弱)

第二个坑点是一开始插入的头结点尾结点的值要是-inf不能是0,否则maxsum更新时会出错。。

最后就是same标记的问题,要特殊处理一下makesame(0)的情况。。

到这里就搞定了,6052MSAC,有点慢。。

#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int inf=99999999,maxn=500005;
int n,m,i,nnode=0,rest=0,root=0,root1,pos,tot,k,q[maxn],c[maxn][2],size[maxn],pre[maxn],num[maxn],maxsum[maxn],maxpre[maxn],maxpos[maxn],same[maxn],rev[maxn],sum[4000005],s[maxn];
char str[10];
void update(int x)
{
	size[x]=size[c[x][0]]+size[c[x][1]]+1;sum[x]=sum[c[x][0]]+sum[c[x][1]]+num[x];
	maxsum[x]=max(max(maxsum[c[x][0]],maxsum[c[x][1]]),maxpos[c[x][0]]+num[x]+maxpre[c[x][1]]);
	maxpre[x]=max(sum[c[x][0]]+maxpre[c[x][1]]+num[x],maxpre[c[x][0]]);maxpos[x]=max(sum[c[x][1]]+maxpos[c[x][0]]+num[x],maxpos[c[x][1]]);
}

void marksame(int x,int c)
{
	same[x]=c;
	if (c==1001) c=0;
	num[x]=c;sum[x]=size[x]*c;
	if (c>=0) maxsum[x]=maxpre[x]=maxpos[x]=size[x]*c; else maxpre[x]=maxpos[x]=0,maxsum[x]=c;
}
void markrev(int x)
{
	swap(c[x][0],c[x][1]);
	swap(maxpre[x],maxpos[x]);
	rev[x]^=1;
}
void down(int x)
{
	if (same[x])
	{
		if (c[x][0]) marksame(c[x][0],same[x]); if (c[x][1]) marksame(c[x][1],same[x]);
		same[x]=0; 
	}
	if (rev[x])
	{
		if (c[x][0]) markrev(c[x][0]);if (c[x][1]) markrev(c[x][1]);
		rev[x]=0;
	}
}
void newnode(int &x,int fa,int k)
{
	if (rest) x=s[rest--];else x=++nnode;
	pre[x]=fa;num[x]=k;	size[x]=1;
	c[x][0]=c[x][1]=same[x]=rev[x]=0;
	sum[x]=maxsum[x]=k;
	maxpre[x]=maxpos[x]=max(k,0);
}
void rot(int x,int kind)
{
	int y=pre[x];int z=pre[y];down(x);
	c[y][!kind]=c[x][kind];pre[c[x][kind]]=y;
	c[x][kind]=y;pre[y]=x;
	pre[x]=z;if (z) c[z][c[z][1]==y]=x;
	update(y);update(x);if (z) update(z);
}
void splay(int x,int goal)
{
	int y,z,kind;
	while (pre[x]!=goal)
	{
		y=pre[x];down(y);
		if (pre[y]==goal) rot(x,c[y][0]==x);
		else
		{
			z=pre[y];down(z);kind=c[z][0]==y;
			if (c[y][!kind]==x) rot(y,kind);else rot(x,!kind);
			rot(x,kind);
		}
	}
	if (goal==0) root=x;
}
int findkth(int x,int k)//加处理 
{
	down(x);
	if (size[c[x][0]]>=k) return findkth(c[x][0],k);
	if (k==size[c[x][0]]+1) return x;
	if (k>size[c[x][0]]+1) return findkth(c[x][1],k-size[c[x][0]]-1);
}
void build(int &x,int fa,int l,int r)
{
	if (l>r) return;
	int mid=(l+r)/2;
	newnode(x,fa,q[mid]);
	if (l==r) return;
	build(c[x][0],x,l,mid-1);build(c[x][1],x,mid+1,r);
	update(x);
}
void insert(int pos,int tot)
{
	int i;
	for (i=1;i<=tot;i++)
		scanf("%d",&q[i]);
	build(root1,0,1,tot);
	splay(findkth(root,pos+1),0);
	splay(findkth(root,pos+2),root);
	c[c[root][1]][0]=root1;pre[root1]=c[root][1];
	update(c[root][1]);update(root);
}
void erase(int x)
{
	if (!x) return;
	s[++rest]=x;
	erase(c[x][0]);erase(c[x][1]);
}
void deleted(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	erase(c[c[root][1]][0]);
	c[c[root][1]][0]=0;
	update(c[root][1]);update(root);
}
void makesame(int pos,int tot,int k)
{
	if (k==0) k=1001;
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	marksame(c[c[root][1]][0],k);
	update(c[root][1]);update(root);
}
void markrev(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	markrev(c[c[root][1]][0]);
	update(c[root][1]);update(root);
	
}
int getsum(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	return sum[c[c[root][1]][0]];
}
void print(int x)
{
	if (c[x][0]) print(c[x][0]);
	printf("%d->num:%d,fa:%d,lc:%d,rc:%d,size:%d,sum:%d,maxpre:%d,maxpos:%d,maxsum:%d,same:%d,rev:%d\n",x,num[x],pre[x],c[x][0],c[x][1],size[x],sum[x],maxpre[x],maxpos[x],maxsum[x],same[x],rev[x]);
	if (c[x][1])print(c[x][1]);
}
int main()
{
	freopen("shulie.in","r",stdin);
	freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	newnode(root,0,-inf);newnode(c[root][1],root,-inf);
	insert(0,n);
	size[0]=pre[0]=same[0]=rev[0]=num[0]=sum[0]=maxpre[0]=maxpos[0]=0;maxsum[0]=-inf;
	for (i=1;i<=m;i++)
	{
		scanf("%s",&str);
		if (str[2]!='X') scanf("%d%d",&pos,&tot); else printf("%d\n",maxsum[root]);
		if (str[0]=='I') insert(pos,tot);
		if (str[0]=='D') deleted(pos,tot);
		if (str[0]=='M'&&str[2]=='K') scanf("%d",&k),makesame(pos,tot,k);
		if (str[0]=='R') markrev(pos,tot);
		if (str[0]=='G') printf("%d\n",getsum(pos,tot));
	}
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值