zoukankan      html  css  js  c++  java
  • codeforce1000C 求线段覆盖次数特殊操作及其拓展

    通过标记起点,使其+1,标记终点后第一个的点,使其-1,然后从头到尾遍历一次,进行类似于前缀和的运算,每次取点的值,当前值为n,表示被n条线段覆盖的区域增加一个

    图解示例:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<vector>
    #include<queue>
    #include<set>
    #include<iomanip>
    #include<cctype> 
    using namespace std;
    const int MAXN=2e5+5;
    const int INF=1<<30;
    const long long mod=1e9+7;
    const double eps=1e-8;
    #define ll long long
    #define edl putchar('
    ')
    #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define ROF(i,a,b) for(int i=a;i>=b;i--)
    #define FORLL(i,a,b) for(ll i=a;i<=b;i++)
    #define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
    #define mst(a) memset(a,0,sizeof(a))
    #define mstn(a,n) memset(a,n,sizeof(a))
    #define zero(x)(((x)>0?(x):-(x))<eps) 
    int n,cnt;
    ll ans[MAXN],las;
    struct num
    {
    	ll l,r;
    }a[MAXN];
    map<ll,int> mp;
    int main()
    {
    	scanf("%d",&n);
    	FOR(i,1,n)
    	scanf("%lld%lld",&a[i].l,&a[i].r);
    	FOR(i,1,n)
    	{
    		mp[a[i].l]++,mp[a[i].r+1]--;
    	}
    	map<ll,int>::iterator it;
    	for(it=mp.begin();it!=mp.end();it++)
    	{
    		if(it==mp.begin())
    		{
    			las=it->first;
    			cnt=0;
    		}
    		ans[cnt]+=it->first-las;
    		cnt+=it->second;
    		las=it->first;
    	}
    	FOR(i,1,n)
    	printf("%lld%c",ans[i],i==n?'
    ':' ');
    }
    

      

    这样的一个思想可以拓展,用于解决一些类似的区间覆盖问题。

     

    拓展一:

    区间染色问题,很简单,再增加一个数组记录颜色即可。

     

    拓展二:

    二维区间(平面覆盖)

    如果把这道题的问题规模扩充到一个平面,要如何处理?

    直接得出一个不同规模的解有些难度,让我们先从已有结论出发:

    标记一个n*m的区间相当于标记长度为m的区间n次,这样一次操作的复杂度是O(n)或O(m)而不是O(1)

    示例:

    我们这样标记就一定要先从左向右处理,然后才能换行,因为这种做法的本质是把平面降成了线,所以要遵循一维的规则(红色区域为覆盖域)。

     注意到一维的规则里,只有上一次的状态(左侧)会对现在的结果产生影响

    因此猜测二维情况下同时与左侧与上侧相关:

    1.处于左边界时,左侧无关联,所以上侧的值要计入当前

    2.处于上边界时,上侧无关联,所以左侧的值要计入当前

    3.处于非边界时,如果同时计入左侧和上侧,会导致值比预期的要大,但如果同时存在上侧和左侧,则左上侧一定存在,减去左上侧的值,那么计数即符合预期。

    得出类似前缀和的算式:(aij)+=(ai-1j)+(aij-1)-(ai-1j-1)

    通过对算式的推演,发现正确的赋值方式如下:

    及其计算的结果:

    符合预期情况。

    牛客网暑期ACM多校训练营(第二场)J题可以用该方法解决

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<vector>
    #include<queue>
    #include<set>
    #include<iomanip>
    #include<cctype> 
    #include<stack>
    #include<ctime>
    using namespace std;
    const int MAXN=1e6+5;
    const int INF=1<<30;
    const long long mod=1e9+7;
    const double eps=1e-8;
    typedef long long ll;
    #define edl putchar('
    ')
    #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define ROF(i,a,b) for(int i=a;i>=b;i--)
    #define FORLL(i,a,b) for(ll i=a;i<=b;i++)
    #define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
    #define mst(a) memset(a,0,sizeof(a))
    #define mstn(a,n) memset(a,n,sizeof(a))
    #define zero(x)(((x)>0?(x):-(x))<eps)
    vector<ll> color[MAXN];
    vector<int> now[MAXN],mp[MAXN];
    int main()
    {
    	int n,m,k,ans;
    	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    	{
    		ans=0;
    		FOR(i,0,n+1)
    		{
                mp[i].resize(m+5);
                now[i].resize(m+5);
                color[i].resize(m+5);
            }
    		FOR(i,1,n)
    		FOR(j,1,m)
    		{
    			scanf("%d",&mp[i][j]);
    			color[i][j]=0;
    			now[i][j]=0;
    		}
    		int x1,y1,x2,y2;
    		ll t;
    		while(k--)
    		{
    			scanf("%d%d%d%d%lld",&x1,&y1,&x2,&y2,&t);
    			color[x1][y1]+=t;
    			color[x1][y2+1]-=t;
    			color[x2+1][y1]-=t;
    			color[x2+1][y2+1]+=t;
    			
    			now[x1][y1]++;
    			now[x1][y2+1]--;
    			now[x2+1][y1]--;
    			now[x2+1][y2+1]++;
    		}
    		FOR(i,1,n)
    		{
    			FOR(j,1,m)
    			{
    				now[i][j]+=now[i-1][j]+now[i][j-1]-now[i-1][j-1];
    				color[i][j]+=color[i-1][j]+color[i][j-1]-color[i-1][j-1];
    				if(now[i][j]>1) ans++;
    				if(now[i][j]==1&&color[i][j]!=mp[i][j])ans++;
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      

    再扩展到三维空间:aijk+=(ai-1jk)+(aij-1k)+(aijk-1)-(ai-1j-1k)-(ai-1jk-1)-(aij-1k-1)+(ai-1j-1k-1)

    赋值ax1y1z1=1,a(x2+1)(y2+1)(z2+1)=1,a其余顶点为-1

  • 相关阅读:
    NABCD项目分析
    周总结6
    移动端展示
    暑期周进度报告(四)
    暑期周进度报告(三)
    暑期周进度报告(二)
    暑期周进度报告(一)
    《人件》阅读笔记02
    周学习进度报告(2020/06/05)
    2020春季软件工程课程总结
  • 原文地址:https://www.cnblogs.com/qq936584671/p/9306178.html
Copyright © 2011-2022 走看看