poj2528 Mayor's posters(线段树的离散化)

2024-04-05 21:18

本文主要是介绍poj2528 Mayor's posters(线段树的离散化),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

题目链接:http://poj.org/problem?id=2528

分析:其实离散化就是将一个很大的区间映射为一个很小的区间,而不改变原有的大小覆盖关系。但是注意简单的离散化可能  会出现错误,给出下面两个简单的例子应该能体现普通离散化的缺陷: 例子一:1-10 1-4 5-10 例子二:1-10 1-4 6-10 普通离散化后都变成了[1,4][1,2][3,4] 线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢? 例子一是完全被覆盖掉了,而例子二没有被覆盖  解决的办法则是对于距离大于1的两相邻点,中间再插入一个点,本题还用到了Lazy标记的思想。

代码:

 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1e4+10;
int s[maxn],e[maxn],lisan[4*maxn],t,n,tmp,vis[maxn],ans;
struct node{int l,r,v;
}tree[16*maxn];int bin(int x){int l=1,r=tmp-1;while(l<=r){int mid=(l+r)>>1;if(lisan[mid]==x) return mid;else if(x<lisan[mid]) r=mid-1;else l=mid+1;}
}void build(int l,int r,int id){tree[id].l=l,tree[id].r=r,tree[id].v=-1;if(l==r) return ;int mid=(l+r)>>1;build(l,mid,2*id);build(mid+1,r,2*id+1);
}void update(int l,int r,int id,int col){if(l<=tree[id].l && tree[id].r<=r){tree[id].v=col;return ;}if(tree[id].v!=-1) {tree[2*id].v=tree[2*id+1].v=tree[id].v;tree[id].v=-1;}int mid=(tree[id].l+tree[id].r)>>1;if(r<=mid) update(l,r,2*id,col);else if(l>mid) update(l,r,2*id+1,col);else update(l,mid,2*id,col),update(mid+1,r,2*id+1,col);
}void query(int l,int r,int id){if(tree[id].v!=-1){if(!vis[tree[id].v]){ans++;vis[tree[id].v]=1;}return ;}if(l==r) return ;int mid=(l+r)>>1;query(l,mid,2*id);query(mid+1,r,2*id+1);
}int main(){///std::ios::sync_with_stdio(false);cin>>t;while(t--){memset(vis,0,sizeof(vis));cin>>n;for(int i=1;i<=n;i++) cin>>s[i]>>e[i];for(int i=1;i<=n;i++) lisan[i]=s[i];for(int i=n+1;i<=2*n;i++) lisan[i]=e[i-n];///离散化sort(lisan+1,lisan+2*n+1);int tot=1;lisan[tot++]=lisan[1];for(int i=1;i<2*n;i++)if(lisan[i+1]!=lisan[i]) lisan[tot++]=lisan[i+1];tmp=tot-1;for(int i=1;i<tot;i++)if(lisan[i+1]-lisan[i]!=1) lisan[++tmp]=lisan[i]+1;sort(lisan+1,lisan+tmp);build(1,tmp-1,1);for(int i=1;i<=n;i++){int L=bin(s[i]),R=bin(e[i]); //二分update(L,R,1,i);}query(1,tmp-1,1);cout<<ans<<endl;ans=0;}
}

线段树的应用

维护区间最大值

void pushup( ll r ) {root[r] = max(root[ls],root[rs]);
}void updata( ll r, ll le, ll ri, ll pos, ll w ) {if( le == ri ) {root[r] = w;return;}ll mid = (le+ri)/2;if( pos <= mid ) {updata(ls,le,mid,pos,w);}if( mid < pos ) {updata(rs,mid+1,ri,pos,w);}pushup(r);
}

 

去重+离散化

//一个n*n的图中有效贡献点有限,可这样离散,注意要写行列贡献相同需去重for( ll i = 1; i <= n; i ++ ) {scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].w);dis[i] = 0, num[i] = a[i].y;}sort(num+1,num+n+1);sz = unique(num+1,num+n+1) - (num+1);  //去重sort(a+1,a+n+1,cmp);a[n+1].x = a[n].x + 1;build(1,1,sz);    //建树

 

 求图贡献最大

//一段区间最大贡献
ll query( ll r, ll le, ll ri, ll L, ll R ) {if( R < le || ri < L ) {return 0;}if( L <= le && ri <= R ) {return root[r];}ll MAX = 0;ll mid = (le+ri)/2;if( L <= mid ) {MAX = max(MAX,query(ls,le,mid,L,R));}if( mid < R ) {MAX = max(MAX,query(rs,mid+1,ri,L,R));}return MAX;
}
dis[i] = query(1,1,sz,1,le-1) + a[i].w;if( a[i].x != a[i+1].x ) {if( dis[i] > root[pos[le]] ) {updata(1,1,sz,le,dis[i]);}for( ll i = 1; i <= cnt; i ++ ) {if( dt[i] > root[pos[st[i]]] ) {updata(1,1,sz,st[i],dt[i]);}}cnt = 0;} else {cnt ++;st[cnt] = le, dt[cnt] = dis[i];}ans = max(ans,dis[i]);

 

 

 区间最大值


void build(int l, int r, int n)
{s[n].l = l;s[n].r = r;s[n].maxx = 0;s[n].minn = N;if(l == r){s[n].maxx = s[n].minn = a[l];return;}int mid = (l + r) >> 1;build(l, mid, n<<1);build(mid + 1, r, n<<1|1);s[n].maxx = max(s[n<<1].maxx, s[n<<1|1].maxx);s[n].minn = min(s[n<<1].minn, s[n<<1|1].minn);
}
void query(int l, int r, int n)
{if(s[n].l == l && s[n].r == r){ans_x = max(ans_x, s[n].maxx);ans_y = min(ans_y, s[n].minn);return;}int mid = (s[n].l + s[n].r) >> 1;if(r <= mid)query(l, r, n<<1);else if(l > mid)query(l, r, n<<1|1);else{query(l, mid, n<<1);query(mid+1, r, n<<1|1);}
}

 

 

这篇关于poj2528 Mayor's posters(线段树的离散化)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/878173

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

HDU4737线段树

题目大意:给定一系列数,F(i,j)表示对从ai到aj连续求或运算,(i<=j)求F(i,j)<=m的总数。 const int Max_N = 100008 ;int sum[Max_N<<2] , x[Max_N] ;int n , m ;void push_up(int t){sum[t] = sum[t<<1] | sum[t<<1|1] ;}void upd

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

圆与线段的交点

poj 3819  给出一条线段的两个端点,再给出n个圆,求出这条线段被所有圆覆盖的部分占了整条线段的百分比。 圆与线段的交点 : 向量AB 的参数方程  P = A + t * (B - A)      0<=t<=1 ; 将点带入圆的方程即可。  注意: 有交点 0 <= t <= 1 ; 此题求覆盖的部分。 则 若求得 t  满足 ; double ask(d

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja