zoukankan      html  css  js  c++  java
  • CF1034D Intervals of Intervals

    一、题目

    点此看题

    二、解法

    (k) 很大还是考虑二分答案,主要是如何检查。

    区间覆盖问题可以考虑染色,一开始所有点都是白色间代表第 (i) 种颜色,后染的颜色会覆盖先染的颜色。染色问题有一个很好的性质:每个点上的颜色都是最后覆盖它的颜色

    根据这个性质我们可以考虑对于固定的右端点,维护出所有左端点的答案,假设现在右端点移动到了 (r),在插入区间 (r) 时,我们考虑它替换了颜色 (x) 的某一段(长度为 (len)),那么对于 (lin(x,r]) 的答案会增加 (len),因为在未插入 (r) 的时候这一段都是白色。

    假设现在的左端点是 (L),我们要维护出左端点取 ([1,L]) 时的价值和,令 (xleftarrow x+1),如果 (x>L),那么暂时不会造成影响,可以打标记解决;如果 (xleq L),那么会有 ((L-x+1)cdot len) 的权值变化,所以这一部分可以 (O(n)) 解决。

    染色的过程需要用 ( t set) 维护,是 (O(nlog n)) 的,但是由于每次检查染色的方式都是一样的,所以我们可以预处理染色,把染色的变化用 ( t vector) 存下来,那么检查就可以做到 (O(n)) 了。

    最后具体讲一下怎么用 ( t set) 维护染色,据说这个叫珂朵莉树,我们首先把要加入的区间添加断点(也就是 ( t lower\_bound) 到包含端点的区间之后把区间按照端点断开),然后把端点中的区间删去,再插入新的区间即可。

    三、总结

    染色是处理区间问题的重要手段,可以用 ( t set) 维护染色过程。

    一段区间产生贡献的题,可以固定右端点,维护出所有左端点的答案。

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <set>
    using namespace std;
    const int M = 300005;
    const int inf = 1e9;
    #define sit set<node>::iterator
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,k,ans,num,res,ad[M];
    struct node
    {
    	int l,r,t;
    	bool operator < (const node &b) const
    	{
    		if(l==b.l) return r<b.r;
    		return l<b.l;
    	}
    };set<node> s;vector<node> g[M];
    sit get(int p)
    {
    	sit it=s.lower_bound(node{p,0,0});
    	if(it!=s.end() && (*it).l==p) return it;
    	it--;
    	if((*it).r==p) return s.end();
    	node t=*it;
    	s.erase(it);
    	s.insert(node{t.l,p,t.t});
    	return s.insert(node{p,t.r,t.t}).first;
    }
    int check(int mid)
    {
    	num=res=0;int val=0,sum=0;
    	for(int i=1;i<=n;i++) ad[i]=0;
    	for(int i=1,L=0;i<=n;i++)
    	{
    		for(int j=0;j<g[i].size();j++)
    		{
    			if(g[i][j].l>L)
    				ad[g[i][j].l]+=g[i][j].r;
    			else
    				val+=g[i][j].r,
    				sum+=g[i][j].r*(L-g[i][j].l+1);
    			ad[i+1]-=g[i][j].r;
    		}
    		for(;L<i && val+ad[L+1]>=mid;L++)
    			val+=ad[L+1],sum+=val;
    		num+=L;res+=sum;
    	}
    	return num;
    }
    signed main()
    {
    	n=read();k=read();
    	s.insert(node{1,inf,0});
    	for(int i=1;i<=n;i++)
    	{
    		int a=read(),b=read();
    		sit r=get(b),l=get(a);
    		for(;l!=r;)
    		{
    			node t=*l;
    			s.erase(l++);
    			//attention OPEN interval
    			g[i].push_back(node{t.t+1,t.r-t.l,0});
    		}
    		s.insert(node{a,b,i});
    	}
    	int l=1,r=inf;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		check(mid);
    		if(num>=k)
    			ans=mid,l=mid+1;
    		else
    			r=mid-1;
    	}
    	printf("%lld
    ",res-ans*(num-k));
    }
    
  • 相关阅读:
    Python基础教程之第2章 列表和元组
    java最简单的方式实现httpget和httppost请求
    90后女生微信销售案例:预热和成熟
    window.onload与$.ready的差别
    在delphi下TClientSocket的使用技巧 转
    delphi安装 Tclientsocket, Tserversocket控件
    DELPHI SOKET 编程(使用TServerSocket和TClientSocket) 转
    Delphi ServerSocket,ClientSocket示例
    Delphi Socket 阻塞线程下为什么不触发OnRead和OnWrite事件
    delphi TServerSocket阻塞线程单元 实例
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15008306.html
Copyright © 2011-2022 走看看