zoukankan      html  css  js  c++  java
  • 6.6 省选模拟赛 线段 二维数点问题 树套树 CDQ分治

    LINK:线段

    还是太菜了 没看出这道题真正的模型 我真是一个典型的没脑子选手。

    考虑如何查询答案。

    每次在一个线段x的状态被更改后 可以发现有影响的是 和x相连那段极长连续1子段。

    设这个子段左端点为l 右端点为r 那么容易发现 左端点为 l~x 右端点为 x~r 这些询问的贡献将会变化。

    将这个变化映射到二维平面上 那么每次询问就是询问某个点的类似的权值。

    考虑一条线段在 T1时刻是联通的 T2时刻不连通了 那么对答案的贡献为T2-T1.

    至此每次修改都可以看成给二维平面上某个区域加上一个值。

    那么对于询问 考虑当前点是否是联通的 如果不连通那就是当前点权 如果联通就是i+当前点权 因为只有不连通的时候贡献才会产生 此时强制性让其不连通即可。

    那么就是一个二维数点问题。经典模型是CDQ分治解决。

    当然一个比较无脑的实现是 线段树套线段树 或者 树状数组套线段树。

    当然内层线段树都需要是 动态开点+标记永久化。下传懒标记对空间开销过大。

    值得一提的是查最远和左右端点的问题 如果采用线段树上二分感觉比往常的要繁琐很多 所以采用的是树状数组+二分 当然也可以二分+set等等。

    这里用的是CDQ分治.

    const int MAXN=300010;
    int n,Q,cnt;
    char a[MAXN];
    int c[MAXN],ans[MAXN];ll s[MAXN];
    struct wy{int x,y,id;int op;}t[MAXN*4],tmp[MAXN*4];
    inline int ask(int x){int cnt=0;while(x)cnt+=c[x],x-=x&-x;return cnt;}
    inline void add(int x,int y){while(x<=n)c[x]+=y,x+=x&-x;}
    inline ll ask1(int x){ll cnt=0;while(x)cnt+=s[x],x-=x&-x;return cnt;}
    inline void add1(int x,int y){while(x<=n)s[x]+=y,x+=x&(-x);}
    inline int check(int l,int r){return ask(r)-ask(l-1)>=r-l+1;}
    inline int askr(int x)
    {
    	if(x==n)return x;
    	if(!check(x+1,x+1))return x;
    	int l=x+1,r=n;
    	while(l+1<r)
    	{
    		int mid=(l+r)>>1;
    		if(check(x+1,mid))l=mid;
    		else r=mid;
    	}
    	if(check(x+1,r))return r;
    	return l;
    }
    inline int askl(int x)
    {
    	if(x==1)return x;
    	if(!check(x-1,x-1))return x;
    	int l=1,r=x-1;
    	while(l<r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid,x-1))r=mid;
    		else l=mid+1;
    	}
    	return r;
    }
    inline void CDQ(int l,int r)//第一维时间 第二维横坐标 第三维纵坐标.
    {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	CDQ(l,mid);
    	CDQ(mid+1,r);//两边都按照横坐标排好序.
    	int i=l,j=mid+1,mark=r;
    	rep(l,r,k)
    	{
    		if(i<=mid&&j<=r)
    		{
    			if(t[i].x<=t[j].x)
    			{
    				if(op(i))add1(t[i].y,op(i));
    				tmp[k]=t[i];++i;
    			}
    			else
    			{
    				if(!op(j))ans[id(j)]+=ask1(t[j].y);
    				tmp[k]=t[j];++j;
    			}
    		}
    		else
    		{
    			mark=min(mark,i-1);
    			if(i<=mid)tmp[k]=t[i],++i;
    			else 
    			{
    				if(!op(j))ans[id(j)]+=ask1(t[j].y);
    				tmp[k]=t[j];++j;mark=mid;
    			}
    		}
    	}
    	rep(l,mark,i)if(op(i))add1(t[i].y,-op(i));
    	rep(l,r,k)t[k]=tmp[k];//归并结束.
    }
    int main()
    {
    	freopen("1.in","r",stdin);
        //freopen("segment.out","w",stdout);
    	gt(n);gt(Q);gc(a);
    	rep(1,n,i)
    	{
    		c[i]+=a[i]-'0';
    		if((i+(i&-i))<=n)c[i+(i&-i)]+=c[i];
    	}
    	rep(1,Q,i)
    	{
    		gc(a);ans[i]=-1;
    		if(a[1]=='q')
    		{
    			int l,r;gt(l),gt(r);--r;
    			int wr=askr(l-1);ans[i]=0;
    			if(wr>=r)ans[i]+=i;//此时是联通的 需要强制断开.
    			t[++cnt]=(wy){l,r,i,0};//查询(1,1) 到 (l,r)的矩形和.
    		}
    		else
    		{
    			int x;gt(x);
    			int wl=askl(x);
    			int wr=askr(x);
    			int ww=check(x,x);
    			if(ww)//当前是联通的.
    			{
    				t[++cnt]=(wy){wl,x,i,i};
    				if(wr+1<=n)t[++cnt]=(wy){wl,wr+1,i,-i};
    				if(x+1<=n)t[++cnt]=(wy){x+1,x,i,-i};
    				if(wr+1<=n)t[++cnt]=(wy){x+1,wr+1,i,i};
    				add(x,-1);
    			}
    			else
    			{
    				t[++cnt]=(wy){wl,x,i,-i};
    				if(wr+1<=n)t[++cnt]=(wy){wl,wr+1,i,i};
    				if(x+1<=n)t[++cnt]=(wy){x+1,x,i,i};
    				if(wr+1<=n)t[++cnt]=(wy){x+1,wr+1,i,-i};
    				add(x,1);
    			}
    		}
    	}
    	CDQ(1,cnt);
    	rep(1,Q,i)if(ans[i]!=-1)put(ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    左偏树
    论在Windows下远程连接Ubuntu
    ZOJ 3711 Give Me Your Hand
    SGU 495. Kids and Prizes
    POJ 2151 Check the difficulty of problems
    CodeForces 148D. Bag of mice
    HDU 3631 Shortest Path
    HDU 1869 六度分离
    HDU 2544 最短路
    HDU 3584 Cube
  • 原文地址:https://www.cnblogs.com/chdy/p/13060997.html
Copyright © 2011-2022 走看看