• Mayor's posters (POJ 2528)线段树+离散化


    n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri (1<=li<=ri<=1e7) 。求出最后还能看见多少张海报。
    Input
    第一行: 样例个数T
    第二行: 贴海报的人n
    第三行: 每个人贴海报的范围
    接下来n行: 每个人贴海报的范围
    Output
    对于每一个输入,输出最后可以看到的海报张数。下面这个图是样例解释
    在这里插入图片描述
    Sample Input
    1
    5
    1 4
    2 6
    8 10
    3 4
    7 10
    Sample Output
    4

    海报张贴的范围是1e7直接线段树是肯定要超时的更别说还多个样例了,但是海报的张数才1e4,所以总的范围内有非常多点是没有用到的,可以把这些点全部省略只保留用到的端点,然后在线段树就方便许多了,然后还有一个问题
    先来个样例吧
    2
    1 5
    1 2
    4 5
    正确答案应该是3,但是直离散化端点后之后求得的是2,在点2和4之间应该还有一段但是离散化端点之后这一段就被省略了,所以我们需要把省略的这一把分再加入离散化里面,只用加一个省略线段之间的任意一点就可以了(如果省略部分长度大于1),这样就能ac啦,这道题数据有点水,不加省略的部分也能ac。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std; 
    typedef long long ll;
    const int N=1e4+10;
    int n,t,a[N],l[N],r[N],idx;
    vector<int> ve;
    struct node
    {
    	int l,r;
    	int id;//表示将整个区间覆盖的报纸编号,0表示不存在完全覆盖
    }tr[N<<4];
    void pushdown(int rt)//只保存能完全覆盖的最小区间,就不用pushup了
    {
    	if(tr[rt].id)
    	{
    		tr[rt<<1|1].id=tr[rt<<1].id=tr[rt].id;
    		tr[rt].id=0;//记得清空
    	}
    }
    void build(int rt,int l,int r)
    {
    	if(l==r) tr[rt]={l,l,0};
    	else 
    	{
    		tr[rt]={l,r};
    		int mid=l+r>>1;
    		build(rt<<1,l,mid);
    		build(rt<<1|1,mid+1,r);
    	}
    }
    void updata(int rt,int l,int r,int d)
    {
    	if(l<=tr[rt].l&&tr[rt].r<=r)
    	{
    		tr[rt].id=d;
    	}
    	else 
    	{
    		pushdown(rt);
    		int mid =tr[rt].l+tr[rt].r>>1;
    		if(l<=mid) updata(rt<<1,l,r,d);
    		if(r>mid) updata(rt<<1|1,l,r,d);
    	}
    }
    int ans;
    bool st[N];
    void query(int rt,int l,int r)
    {
    	if(tr[rt].id)
    	{
    		if(!st[tr[rt].id])
    		{
    	  		ans++;
    	  		st[tr[rt].id]=1;
    	  	}
    	  	return ;
    	}
    	if(tr[rt].l==tr[rt].r) return ;//记得及时结束
    	pushdown(rt);
    	int mid=tr[rt].l+tr[rt].r>>1;
    	if(l<=mid) query(rt<<1,l,r);
    	if(r>mid) query(rt<<1|1,l,r);
    }
    int main()
    {
    	
    	scanf("%d",&t);
    	while(t--)
    	{
    		scanf("%d",&n);
    		ve.clear();
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d%d",l+i,r+i);
    			ve.push_back(l[i]);
    			ve.push_back(r[i]);
    		}
    		sort(ve.begin(),ve.end());
    		ve.erase(unique(ve.begin(),ve.end()),ve.end());//去重
    		int sz=ve.size();//一定要加这一步,因为后面遍历的途中ve.size()就在变化,会一直向里面再加多余的点直到MLE
    		for(int i=1;i<sz;i++)
    			if(ve[i]-ve[i-1]>1) ve.push_back((ve[i]-1));
    		sort(ve.begin(),ve.end());
    		build(1,1,ve.size());
    		for(int i=1;i<=n;i++)
    		{
    			int x=lower_bound(ve.begin(),ve.end(),l[i])-ve.begin()+1;//我想要端点从1开始
    			int y=lower_bound(ve.begin(),ve.end(),r[i])-ve.begin()+1;
    			updata(1,x,y,i);
    		}
    		ans=0;
    		memset(st,0,sizeof st);
    		query(1,1,ve.size());
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    字符串与Json操作
    默认让IE用最高文档模式浏览网页
    MVC中简单的文件下载代码
    2017年1月22日
    JDK环境变量设置
    如何实现windows命令提示符的tab补全
    win7热点设置
    为什么小米5不能适配win7
    各种错误锦集
    插头DP
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871751.html
Copyright © 2020-2023  润新知