zoukankan      html  css  js  c++  java
  • [bzoj1582][Usaco2009 Hol]Holiday Painting 节日画画_线段树

    Holiday Painting 节日画画 bzoj-1582 Usaco-2009 Hol

    题目大意:给定两个n*m的01网格图。q次操作,每次将第二个网格图的子矩阵全部变成0或1,问每一次操作后两个网格图有多少个格子不一样。

    注释:$1le nle 5cdot 10^4$,$1le mle 15$,$1le qle 10^4$。


    想法:由于网格图的列比较少,很容易想到对每行建立一棵线段树。

    然后就是线段树上维护的东西:我们考虑直接维护成对应区间中有多少不一样的格子数。

    这个属性显然满足可加性。修改怎么办?

    修改的时候就是再处理出第一个网格图的区间0的个数。如果赋成0信息就变成区间长度减去0的个数,如果是1信息就是区间0的个数。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 50001 
    #define root 1,1,n
    #define ls now<<1,l,mid
    #define rs now<<1|1,mid+1,r
    
    int n,m,q,res;
    int ans[16][N<<2],sum[16][N][2],add[16][N<<2];
    char s[N];
    inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
    int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
    void build(int id,int now,int l,int r)
    {
    	if(l==r)
    	{
    		ans[id][now]=sum[id][l][0]-sum[id][l-1][0];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(id,ls);
    	build(id,rs);
    	ans[id][now]=ans[id][now<<1]+ans[id][now<<1|1];
    }
    
    inline void pushdown(int id,int now,int l,int r)
    {
    	if(add[id][now]^-1)
    	{
    		int mid=(l+r)>>1;
    		add[id][now<<1]=add[id][now];
    		add[id][now<<1|1]=add[id][now];
    		ans[id][now<<1]=sum[id][mid][add[id][now]]-sum[id][l-1][add[id][now]];
    		ans[id][now<<1|1]=sum[id][r][add[id][now]]-sum[id][mid][add[id][now]];
    		add[id][now]=-1;
    	}
    }
    inline void update(int id,int now,int l,int r,int x,int y,int c)
    {
    	if(x<=l&&r<=y)
    	{
    		add[id][now]=c;
    		ans[id][now]=sum[id][r][c]-sum[id][l-1][c];
    		return;
    	}
    	pushdown(id,now,l,r);
    	int mid=(l+r)>>1;
    	if(x<=mid) update(id,ls,x,y,c);
    	if(mid<y) update(id,rs,x,y,c);
    	ans[id][now]=ans[id][now<<1]+ans[id][now<<1|1];
    }
    int main()
    {
    	int i,j,r1,r2,c1,c2,x;
    	n=rd(),m=rd(),q=rd();
    	for(i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		for(j=1;j<=m;j++)
    		{
    			sum[j][i][0]=sum[j][i-1][0]+(s[j]=='0');
    			sum[j][i][1]=sum[j][i-1][1]+(s[j]=='1');
    		}
    	}
    	for(i=1;i<=m;i++)build(i,root);
    	memset(add,-1,sizeof(add));
    	while(q--)
    	{
    		r1=rd(),r2=rd(),c1=rd(),c2=rd();
    		x=rd();
    		res=0;
    		for(i=c1;i<=c2;i++)
    			update(i,root,r1,r2,x);
    		for(i=1;i<=m;i++)res+=ans[i][1];
    		printf("%d
    ",res);
    	}
    	return 0;
    }
    

    小结:线段树使用起来是极其灵活的哦。

  • 相关阅读:
    C# API 大全
    也说_T、_TEXT、TEXT、L
    项脊轩志--归有光
    C# tostring()汇总
    StructLayout特性
    关于C#静态构造函数的几点说明
    C#生成DLL文件
    做.net的早晚会用到,并且网上还没有这方面的正确资料或几乎很少
    C# 实现屏幕键盘 (ScreenKeyboard)
    Microsoft .NET Native
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9675240.html
Copyright © 2011-2022 走看看