华山论剑(nyoj 856)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/woyuhuaijin/article/details/51471235

是一道区间更新的题,先说题意。

编号[l,r]共r-l+1个剑客一起决斗,x胜出,那么从l到r都标记为x,x为0,反复决斗,其中有可能胜出的人再被其他人打败,要求输出每一个剑客第一次被这个剑客打败的编号。

乍一看就是用线段树去做,但是每次都更新到点会超时,所以要用到标记。

用一个标记数组,若当前的区间已经全部被修改了,那么以后不需要再查询这个区间了,注意是这个区间全部的点,因为每一次战斗都有一个获胜者是不需要修改的。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#define lson l,m,level*2
#define rson m+1,r,level*2+1
using namespace std;
int t[301000*5];	//线段树 
int lazy[301000*5];	//标记数组 
void output(int l,int r,int level);
int insert(int l,int r,int level,int x,int y,int z);
int n,m;
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(t,0,sizeof(t));
		memset(lazy,0,sizeof(lazy));
		for(int i=0;i<m;i++){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			insert(1,n,1,x,y,z);
		}
		output(1,n,1);
	}
	return 0;
}

void output(int l,int r,int level){
	if(l==r){
		printf("%d",t[level]);
		if(l==n)	printf("\n");
		else printf(" ");
		return ;
	}
	int m = (l+r)>>1;
	output(lson);
	output(rson);
}
//更新到点 
int insert(int l,int r,int level,int x,int y,int z){
	if(lazy[level])	return lazy[level];	//当该区域已经全部被修改过了,则不需要再修改了 
	if(l==r){	//该点 
		if(l==x&&t[level]==0&&l!=z){
			t[level] = z;
			lazy[level] = 1; 
		} 
		return lazy[level];
	}
	int m = (l+r)>>1;
	if(y<=m){
		insert(lson,x,y,z);
	}
	else if(x>m){
		insert(rson,x,y,z);
	}
	else{
		int t = 0;
		t += insert(lson,x,m,z);
		t += insert(rson,m+1,y,z);
		if(t==2)	lazy[level] = 1;	//只有这种情况才会区域全部修改过 
	}
	return lazy[level];
}        


一开始写的没有思路,看了大神的代码~贴一下膜拜

链接:http://blog.csdn.net/y990041769/article/details/12882095

用了状态压缩的写法,用一个数组保存当前这个点之后的没有被修改过的点,每次修改一个区间,总是修改没有修改过的点。

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int t[301000];	//保存当前点之后的第一个没有被修改过的点 
int ans[301000];	//结果 
//初始化 
void init(int n){
	for(int i=0;i<=n+1;i++){
		t[i] = i;	//当前的每一个点都没有修改过 
		ans[i] = 0;	//每一个都是获胜者 
	}
}
//查找本点及之后第一个没有被修改过的点 
int find(int x){
	if(x==t[x])	return x;
	else{
		t[x] = find(t[x]);
		return t[x];
	}
}

int main(){
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF){
		init(n);
		for(int i=0;i<m;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		for(int j=find(x);j<=y;j = find(j+1)){
			if(j==z)	continue;		//若该点胜利,不需修改 
			ans[j] = z;		//否则写入胜者标号 
			if(j<z)	t[j] = z;	//若该点小于胜利者,则下一个未标记点与胜利者保存的未标记点相同 
			else t[j] = t[y+1];	//否则下一个未标记点为该区域之后的第一个未标记点 
		}
		}
	for(int i=1;i<=n;i++){
		printf("%d",ans[i]);
		if(i==n)	printf("\n");
		else printf(" ");
	}
}
	return 0;
}




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页