zoukankan      html  css  js  c++  java
  • bzoj2658[ZJOI2012]小蓝的好友(mrx)

    题目链接
    校内模拟赛出了这题,然后考试时写出了一个做法,评测机貌似有点慢被卡成90了,原题上可以A掉。首先可以知道(O(n^2))的做法,就是只算全0的矩形个数,枚举下边界是哪一行,定义(h)值表示这个点向上碰到的第一个1的距离,然后可以从左到右枚举右边界,用单调栈维护以每个列作为左边界的矩形最大高度,那么以某一列作为右边界的对答案的贡献就是单调栈中的元素和。
    然后数据随机,可以进一步优化这个做法,用线段树存每个点的高度值,当下边界向下移动时,相当于每个点的高度+1,且新出现的1位置的要设置成0。设新出现1的位置为x,由于每个跨过x的矩形的贡献都是0,要把它减掉,我们按照(O(n^2))的想法,把x左边的单调栈通过线段树给做出来,然后显然后面的点r如果影响到了x以左的单调栈(就是存在一个(lle x)(l)$r-1$的矩形最大高度与$l$(r)的最大矩形高度不同),才会使贡献变化(若没有影响贡献不变,直接用原来的贡献乘区间长度即可),然后就维护一下x以左的单调栈。为了找到这样的r,可以从x开始每次往右找第一个高度小于x的点,x跳过去,这样的每个点都是会影响贡献值的点。
    复杂度(O(qklogn)),k是"从一个点开始每次向右跳到第一个比它小的点的期望跳的次数",由于数据随机k的平均大小是小于(logn)级别的。
    刚刚去看了看别人的做法,怎么都是用treap啊,只能说想不到想不到。实际运行速度我的做法顶多比treap慢一倍的样子,可能是因为线段树比treap快了蛮多吧。
    (O(n^2))的:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    #define P puts("lala")
    #define cp cerr<<"lala"<<endl
    #define ln putchar('
    ')
    #define pb push_back
    #define fi first
    #define se second 
    #define shmem(x) cerr<<sizeof(x)/(1024*1024.0)<<"MB"
    using namespace std;
    inline int read()
    {
        char ch=getchar();int g=1,re=0;
        while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
        while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
        return re*g;
    }
    typedef long long ll;
    typedef pair<int,int> pii;
    
    const int N=2050;
    int dot[N][N],up[N][N];
    int n,m,T;
    pii stk[N]; int top=0;
    
    void wj()
    {
    	freopen("alice.in","r",stdin);
    	freopen("alice.out","w",stdout);
    }
    int main()
    {
    	wj();
    	n=read(); m=read(); T=read();
    	for(int i=1;i<=T;++i) dot[read()][read()]=1;
    	for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)
    		up[i][j]=(dot[i][j]?0:up[i-1][j]+1);
    	ll ans=0;
    	for(int i=1;i<=n;++i)
    	{
    		ll sum=0;
    		for(int j=1;j<=m;++j)
    		{
    			pii v=pii(up[i][j],1);
    			while(top&&stk[top].fi>=v.fi) 
    			{
    				sum-=1ll*stk[top].fi*stk[top].se;
    				v.se+=stk[top].se;
    				top--;
    			}
    			stk[++top]=v;
    			sum+=1ll*v.fi*v.se;
    			ans+=sum;
    		}
    	}
    	printf("%lld
    ",(1ll*n*(n+1)/2)*(1ll*m*(m+1)/2)-ans);
    	return 0;
    }
    

    (O(qklogn))的:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    #include<ctime>
    #define P puts("lala")
    #define cp cerr<<"lala"<<endl
    #define ln putchar('
    ')
    #define pb push_back
    #define fi first
    #define se second 
    #define shmem(x) cerr<<sizeof(x)/(1024*1024.0)<<"MB"
    using namespace std;
    inline int read()
    {
        char ch=getchar();int g=1,re=0;
        while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
        while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
        return re*g;
    }
    typedef long long ll;
    typedef pair<int,int> pii;
    
    const int N=70050;
    int n,m,T;
    int minv[N<<2],addv[N<<2],add=0;
    inline void modify(int o,int l,int r,int x,int k)
    {
    	if(l==r) {minv[o]=k; return ;}
    	int mid=l+r>>1;
    	if(x<=mid) modify(o<<1,l,mid,x,k);
    	else modify(o<<1|1,mid+1,r,x,k);
    	minv[o]=min(minv[o<<1],minv[o<<1|1]);
    }
    inline int query(int o,int l,int r,int x)
    {
    	if(l==r) return minv[o];
    	int mid=l+r>>1;
    	if(x<=mid) return query(o<<1,l,mid,x);
    	else return query(o<<1|1,mid+1,r,x);
    }
    int ret=0,found=0,val;
    inline void gorig(int o,int l,int r,int x)
    {
    	if(l==r) {if(minv[o]<x) ret=l,found=1,val=minv[o];return ;}
    	int mid=l+r>>1;
    	if(minv[o<<1|1]<x) gorig(o<<1|1,mid+1,r,x);
    	else gorig(o<<1,l,mid,x);
    }
    inline void findpre(int o,int l,int r,int x,int y,int k)
    {
    	if(found) return ;
    	if(x<=l&&r<=y) 
    	{
    		if(minv[o]<k) gorig(o,l,r,k);
    		return ;
    	}
    	int mid=l+r>>1;
    	if(y>mid) findpre(o<<1|1,mid+1,r,x,y,k);
    	if(x<=mid) findpre(o<<1,l,mid,x,y,k);
    }
    inline int getpre(int x,int y,int k)
    {
    	if(x>y) return 0;
    	ret=0; found=0; val=0; findpre(1,1,m,x,y,k);
    	return ret;
    }
    inline void golef(int o,int l,int r,int x)
    {
    	if(l==r) {if(minv[o]<x) ret=l,found=1,val=minv[o];return ;}
    	int mid=l+r>>1;
    	if(minv[o<<1]<x) golef(o<<1,l,mid,x);
    	else golef(o<<1|1,mid+1,r,x);
    }
    inline void findnex(int o,int l,int r,int x,int y,int k)
    {
    	if(found) return ;
    	if(x<=l&&r<=y) 
    	{
    		if(minv[o]<k) golef(o,l,r,k);
    		return ;
    	}
    	int mid=l+r>>1;
    	if(x<=mid) findnex(o<<1,l,mid,x,y,k);
    	if(y>mid) findnex(o<<1|1,mid+1,r,x,y,k);
    }
    inline int getnex(int x,int y,int k)
    {
    	if(x>y) return m+1;
    	ret=m+1; found=0; val=0; findnex(1,1,m,x,y,k);
    	return ret;
    }
    
    pii stk[N],stk2[N]; int top=0,top2=0;
    vector<int>ask[N];
    
    void wj()
    {
    	freopen("alice.in","r",stdin);
    	freopen("alice.out","w",stdout);
    }
    int main()
    {
    	wj();
    	clock_t sta=clock();
    	n=read(); m=read(); T=read();
    	for(int i=1;i<=T;++i) 
    	{
    		int x=read(),y=read();
    		ask[x].pb(y);
    	}
    	ll ans=0,sum=0;
    	for(int row=1;row<=n;++row)
    	{
    		add++;
    		sum+=1ll*(m+1)*m/2;
    		for(int i=0,siz=ask[row].size();i<siz;++i)
    		{
    			top=0; top2=0;
    			int in=ask[row][i];
    			ll tot=0;
    			int hi=query(1,1,m,in);
    			while(in)
    			{
    				int las=getpre(1,in-1,hi);
    				stk2[++top2]=pii(hi,in-las);
    				sum-=1ll*(hi+add)*(in-las);
    				tot+=1ll*(hi+add)*(in-las);
    				in=las; hi=val;
    			}
    
    			top=top2;
    			for(int j=1;j<=top;++j) stk[top-j+1]=stk2[j];
    			in=ask[row][i];
    
    			hi=query(1,1,m,in);
    			while(in<=m)
    			{
    				int las=getnex(in+1,m,hi);
    				sum-=1ll*(las-in)*tot;
    				if(in==ask[row][i]) sum+=tot;
    
    				if(las>m) break;
    				pii v=pii((hi=val),0);
    				while(top&&stk[top].fi>=v.fi) 
    				{
    					tot-=1ll*(stk[top].fi+add)*stk[top].se;
    					v.se+=stk[top].se;
    					top--;
    				}
    				stk[++top]=v;
    				tot+=1ll*(v.fi+add)*v.se;
    				in=las;
    			}
    			modify(1,1,m,ask[row][i],-add);
    		}
    		ans+=sum;
    	}
    	printf("%lld
    ",(1ll*n*(n+1)/2)*(1ll*m*(m+1)/2)-ans);
    	//cerr<<(1ll*n*(n+1)/2)*(1ll*m*(m+1)/2)-ans<<endl;
    	clock_t fin=clock();
    	//cerr<<(double)(fin-sta)/CLOCKS_PER_SEC<<endl;
    	return 0;
    }
    
  • 相关阅读:
    CSS命名
    纯html网页重定向与跳转
    display:none与visible:hidden的区别
    添加弹窗视频
    表格
    get请求报文
    解决maven下载jar慢的问题(如何更换Maven下载源)
    Java开发第一步:JDK 7 安装及配置
    安卓开发第一步:Android Studio安装配置
    IntelliJ IDEA 导入新项目以后的简单配置
  • 原文地址:https://www.cnblogs.com/thkkk/p/8491922.html
Copyright © 2011-2022 走看看