华山论剑(nyoj 856)

来源:互联网 发布:ubuntu搭建博客 编辑:程序博客网 时间:2024/04/27 23:17

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

编号[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+1using 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;}




0 0
原创粉丝点击