zoukankan      html  css  js  c++  java
  • 【XSY2707】snow 线段树 并查集

    题目描述

      有(n)个人和一条长度为(t)的线段,每个人还有一个工作范围(是一个区间)。最开始整条线段都是白的。定义每个人的工作长度是这个人的工作范围中白色部分的长度(会随着线段改变而改变)。每一天开始时你要选择一个人满足这个人的工作长度最小(如果有多个就选编号最小的)。把这个人的工作区间染黑。请你输出每天你选了哪个人。

      保证工作范围中左端点和右端点单调递增。

      (nleq 300000)

    题解

      先把线段离散化成很多个小区间,那么每个小区间只会被染黑一次(染黑之后不会变白)。

      因此每次选择了一个人后可以暴力把这个人的工作范围内白色的区间染黑,那么覆盖了这个区间的人就会受到影响。

      观察到左右端点都单调递增,所以覆盖一个区间的人就是连续的。

      直接用线段树维护每个人当前的工作长度。

      用并查集维护右边的第一个白色区间。

      时间复杂度:(O(nlog n))

    代码

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<utility>
    #include<cstring>
    using namespace std;
    typedef pair<int,int> pii;
    int a[2000010];
    int c[2000010];
    int d[2000010];
    int f[2000010];
    int l[2000010];
    int r[2000010];
    int s[2000010];
    int rt;
    namespace seg
    {
    	struct node
    	{
    		int l,r,ls,rs;
    		int t;
    		pii s;
    		node()
    		{
    			l=r=ls=rs=t=0;
    		}
    	};
    	node a[2000010];
    	int cnt;
    	void build(int &p,int l,int r)
    	{
    		p=++cnt;
    		a[p].l=l;
    		a[p].r=r;
    		if(l==r)
    		{
    			a[p].s=pii(::s[l],l);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(a[p].ls,l,mid);
    		build(a[p].rs,mid+1,r);
    		a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
    	}
    	void add(int p,int v)
    	{
    		a[p].t+=v;
    		a[p].s.first+=v;
    	}
    	void push(int p)
    	{
    		if(a[p].t&&a[p].l!=a[p].r)
    		{
    			add(a[p].ls,a[p].t);
    			add(a[p].rs,a[p].t);
    			a[p].t=0;
    		}
    	}
    	void add(int p,int l,int r,int v)
    	{
    		if(l<=a[p].l&&r>=a[p].r)
    		{
    			add(p,v);
    			return;
    		}
    		push(p);
    		int mid=(a[p].l+a[p].r)>>1;
    		if(l<=mid)
    			add(a[p].ls,l,r,v);
    		if(r>mid)
    			add(a[p].rs,l,r,v);
    		a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
    	}
    	void gao(int p,int x)
    	{
    		if(a[p].l==a[p].r)
    		{
    			a[p].s.first=0x7fffffff;
    			return;
    		}
    		push(p);
    		int mid=(a[p].l+a[p].r)>>1;
    		if(x<=mid)
    			gao(a[p].ls,x);
    		else
    			gao(a[p].rs,x);
    		a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
    	}
    	int get(int p,int x)
    	{
    		if(a[p].l==a[p].r)
    			return a[p].s.first;
    		push(p);
    		int mid=(a[p].l+a[p].r)>>1;
    		if(x<=mid)
    			return get(a[p].ls,x);
    		else
    			return get(a[p].rs,x);
    	}
    }
    int find(int x)
    {
    	return f[x]==x?x:f[x]=find(f[x]);
    }
    int b[1000010];
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	int n,t;
    	scanf("%d%d",&t,&n);
    	int m=0;
    	int i;
    	memset(a,0,sizeof a);
    	memset(c,0,sizeof c);
    	memset(d,0,sizeof d);
    	memset(f,0,sizeof f);
    	memset(s,0,sizeof s);
    	memset(l,0,sizeof l);
    	memset(r,0,sizeof r);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&l[i],&r[i]);
    		r[i]--;
    		s[i]=r[i]-l[i]+1;
    		a[++m]=l[i];
    		a[++m]=r[i]+1;
    	}
    	sort(a+1,a+m+1);
    	m=unique(a+1,a+m+1)-a-1;
    	for(i=1;i<=n;i++)
    	{
    		int x=l[i],y=r[i];
    		l[i]=lower_bound(a+1,a+m+1,l[i])-a;
    		r[i]=lower_bound(a+1,a+m+1,r[i]+1)-a-1;
    		if(a[l[i]]!=x)
    			printf("error
    ");
    		if(a[r[i]+1]!=y+1)
    			printf("error
    ");
    		if(l[i]<=l[i-1])
    			printf("error
    ");
    		if(r[i]<=r[i-1])
    			printf("error
    ");
    	}
    	seg::cnt=0;
    	rt=0;
    	seg::build(rt,1,n);
    	for(i=1;i<=m;i++)
    	{
    		c[i]=a[i+1]-a[i];
    		f[i]=i;
    	}
    	f[m+1]=m+1;
    	int j;
    	for(i=1;i<=n;i++)
    	{
    		pii ans=seg::a[rt].s;
    //		printf("%d %d
    ",seg::get(rt,7396),seg::get(rt,20692));
    		printf("%d
    ",ans.second);
    //		seg::add(rt,ans.second,ans.second,0x7fffffff-ans.first);
    		seg::gao(rt,ans.second);
    //		for(j=l[ans.second];j<=r[ans.second];j++)
    //			if(!b[j])
    //			{
    //				b[j]=1;
    		for(j=find(l[ans.second]);j<=r[ans.second];j=find(j))
    		{
    			int x=lower_bound(r+1,r+n+1,j)-r;
    			int y=upper_bound(l+1,l+n+1,j)-l-1;
    			if(x<=y)
    			{
    //				if(r[x-1]>=j)
    //					printf("error1
    ");
    //				if(l[y+1]<=j)
    //					printf("error2
    ");
    				seg::add(rt,x,y,-c[j]);
    			}
    //			else
    //				if(l[7396]<=j&&r[7396]>=j)
    	//				seg::add(rt,7396,7396,-c[j]);
    			f[j]=j+1;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Git命令与使用
    Android与WebView的JS交互
    Android 中关于硬件加速的使用和问题
    Activity-生命周期和启动模式
    Activity-恢复与保存状态或数据
    Android中Paint的一些使用心得记录
    Java中sleep,wait的区别
    C#基本类型
    LeetCode74 搜索二维矩阵
    leetcode 43 字符串相乘 java
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513567.html
Copyright © 2011-2022 走看看