zoukankan      html  css  js  c++  java
  • 线段树练习

    一键挖矿
    https://www.cnblogs.com/ctmlpfs/p/13858405.html

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2000010
    #define int long long
    #define f(x) (x==1||x==3)
    int n,m,tg[N],x[N],y[N],tx[4]={1,-1,1,-1},ty[4]={1,1,-1,-1},ans;
    vector<int>v[N];
    struct va{
    	int x,c;
    }c[N];
    va operator +(va x,va y){
    	va z=(va){min(x.x,y.x),0};
    	if(z.x==x.x)
    		z.c+=x.c;
    	if(z.x==y.x)
    		z.c+=y.c;
    	return z;
    }
    void pd(int o){
    	if(tg[o]){
    		tg[o*2]+=tg[o];
    		tg[o*2+1]+=tg[o];
    		c[o*2].x+=tg[o];
    		c[o*2+1].x+=tg[o];
    		tg[o]=0;
    	}
    }
    void up(int o){
    	c[o]=c[o*2]+c[o*2+1];
    }
    void ad(int o,int l,int r,int x,int y,int z){
    	if(r<x||y<l)
    		return;
    	if(x<=l&&r<=y){
    		tg[o]+=z;
    		c[o].x+=z;
    		return;
    	}
    	int md=(l+r)/2;
    	pd(o);
    	ad(o*2,l,md,x,y,z);
    	ad(o*2+1,md+1,r,x,y,z);
    	up(o);
    }
    va qc(int o,int l,int r,int x,int y){
    	if(r<x||y<l)
    		return (va){n*m+1,0};
    	if(x<=l&&r<=y)
    		return c[o];
    	pd(o);
    	int md=(l+r)/2;
    	return qc(o*2,l,md,x,y)+qc(o*2+1,md+1,r,x,y);
    }
    void bd(int o,int l,int r){
    	if(l==r){
    		c[o].c=1;
    		return;
    	}
    	int md=(l+r)/2;
    	bd(o*2,l,md);
    	bd(o*2+1,md+1,r);
    	up(o);
    }
    void av(int a,int b,int c,int d){
    	int e[5]={0,a,b,c,d};
    	sort(e+1,e+5);
    	int p=lower_bound(e+1,e+5,a)-e;
    	for(int i=1;i<=p;i++){
    		int v=f(p-i+1)-f(p-i);
    		ad(1,1,n*m,e[i-1]+1,e[i],v);
    	}
    }
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=0;i<=n+1;i++)
    		v[i].resize(m+5);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			scanf("%lld",&v[i][j]);
    			x[v[i][j]]=i;
    			y[v[i][j]]=j;
    		}
    	bd(1,1,n*m);
    	for(int j=0;j<=m+1;j++)
    		v[0][j]=v[n+1][j]=n*m+1;
    	for(int i=0;i<=n+1;i++)
    		v[i][0]=v[i][m+1]=n*m+1;
    	for(int i=1;i<=n*m;i++){
    		int a=x[i],b=y[i];
    		for(int j=0;j<4;j++)
    			av(v[a][b],v[a+tx[j]][b],v[a][b+ty[j]],v[a+tx[j]][b+ty[j]]);
    		va tv=(va){4,0};
    		tv=tv+qc(1,1,n*m,1,i);
    		ans+=tv.c;
    	}
    	printf("%lld",ans);
    }
    

    斑斓之地
    定义被蛇覆盖过的点为关键点,没有覆盖的为非关键点。
    题目要算在某个矩形中非关键点连通块个数,可以使用平面图的euler定理(|V|-|E|+|F|=)连通块数。
    计算(|V|)相当于让我们计算矩形([a,b],[l,r])的非关键点个数。
    考虑容斥成((r-l+1)*(b-a+1)-)关键点个数。
    这可以简单的使用可持久化线段树维护。
    计算(|E|)可以计算横的边和竖的边,这同样也是个简单的二维数点问题。
    问题转化为计算(|F|)
    原图的连通区域由两种组成:
    第一个是一个(1*1)的矩形。实际上我们要计算的就是包含(4)个非关键点的(2*2)矩形。
    这也可以使用可持久化线段树维护。
    但是这个算法还有错误。
    可能所有关键点被这个矩形包含了。
    我们在上面没有考虑。
    设关键点的最小(x)坐标为(mnx),最大(x)坐标为(mxx)
    最小(y)坐标为(mny),最大(x)坐标为(mxy)
    (a<mnx)(l<mny)(mxx<b)(mxy<r)(|F|)要+1。
    时间复杂度(O(nmlog_2nm))

    #include<bits/stdc++.h>
    using namespace std;
    #define N 200010
    #define int long long
    char s[N];
    int r,c,m,q,sr,sc,mxx,mnx,mxy,mny,a[N];
    vector<int>v[4][N];
    struct sgt{
    	int lc[N*20],rc[N*20],ct,sz[N*20],rt[N];
    	void ad(int &o,int p,int l,int r,int x){
    		o=++ct;
    		sz[o]=sz[p]+1;
    		lc[o]=lc[p];
    		rc[o]=rc[p];
    		if(l==r)
    			return;
    		int md=(l+r)/2;
    		if(x<=md)
    			ad(lc[o],lc[p],l,md,x);
    		else
    			ad(rc[o],rc[p],md+1,r,x);
    	}
    	int qu(int o,int l,int r,int x,int y){
    		if(r<x||y<l)
    			return 0;
    		if(x<=l&&r<=y)
    			return sz[o];
    		int md=(l+r)/2;
    		return qu(lc[o],l,md,x,y)+qu(rc[o],md+1,r,x,y);
    	}
    	int qq(int l,int r,int a,int b){
    		if(l>r||a>b)
    			return 0;
    		return qu(rt[r+1],0,c,a,b)-qu(rt[l],0,c,a,b);
    	}
    }sg[4];
    void ad(int x,int y){
    	x++;
    	y++;
    	v[0][x].push_back(y);
    	v[1][x-1].push_back(y);
    	v[1][x].push_back(y);
    	v[2][x].push_back(y);
    	v[2][x].push_back(y-1);
    	v[3][x].push_back(y);
    	v[3][x-1].push_back(y);
    	v[3][x].push_back(y-1);
    	v[3][x-1].push_back(y-1);
    }
    signed main(){
    	scanf("%lld%lld%lld%lld%lld%lld%s",&r,&c,&m,&q,&sr,&sc,s+1);
    	sr--;
    	sc--;
    	mxx=mnx=sr;
    	mxy=mny=sc;
    	ad(sr,sc);
    	for(int i=1;i<=m;i++){
    		if(s[i]=='N')
    			sr--;
    		if(s[i]=='S')
    			sr++;
    		if(s[i]=='E')
    			sc++;
    		if(s[i]=='W')
    			sc--;
    		ad(sr,sc);
    		mxx=max(mxx,sr);
    		mnx=min(mnx,sr);
    		mxy=max(mxy,sc);
    		mny=min(mny,sc);
    	}
    	for(int i=0;i<4;i++)
    		for(int j=0;j<=r;j++){
    			sg[i].rt[j+1]=sg[i].rt[j];
    			int le=v[i][j].size();
    			for(int k=0;k<v[i][j].size();k++)
    				a[k]=v[i][j][k];
    			sort(a,a+le);
    			le=unique(a,a+le)-a;
    			for(int k=0;k<le;k++)
    				sg[i].ad(sg[i].rt[j+1],sg[i].rt[j+1],0,c,a[k]);
    		}
    	for(int i=1;i<=q;i++){
    		int a,b,c,d;
    		scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    		a--;
    		b--;
    		c--;
    		d--;
    		int ans=(c-a+1)*(d-b+1)-sg[0].qq(a+1,c+1,b+1,d+1);
    		ans-=(c-a)*(d-b+1)-sg[1].qq(a+1,c,b+1,d+1);
    		ans-=(c-a+1)*(d-b)-sg[2].qq(a+1,c+1,b+1,d);
    		ans+=(c-a)*(d-b)-sg[3].qq(a+1,c,b+1,d);
    		if(a<mnx&&mxx<c&&b<mny&&mxy<d)
    			ans++;
    		printf("%lld
    ",ans);
    	}
    }
    

    扫除
    https://www.cnblogs.com/ctmlpfs/p/13858306.html

    小球进洞
    一个和网上题解不同,个人认为比较巧妙的理解方式:
    把洞看为(,把小球看为),则问题转化成:
    设一个小球的位置为(a_i),它匹配的位置为(b_i),则询问

    绯色IOI(悬念)
    题目的(min(j-a_i,a_i-j))中,(j-a_i)(a_i-j)互为相反数。设为(b_i)(n-b_i)
    题目要求匹配的限制:
    (j-a_i=b_i)就是(j=a_i+b_i)
    (a_i-j=b_i)就是(j=a_i-b_i)
    (j-a_i=-b_i)就是(j=a_i-b_i)
    (a_i-j=-b_i)就是(j=a_i+b_i)
    综上,(j)最多只有(2)种取值。
    把这两种取值在右边连一条边,则每个二分图左边点最多会产生1条边的贡献。
    根据hall定理,二分图左边每个集合(S)覆盖右边的集合(R(S))(card(R(s))>=card(S))。所以右边的每个连通块都是树或者基环树。
    每个左边的点最多和一个右边点进行匹配。假设一个左边的点连接右边的第一种权值的点(a)获得权值(v1),连接(b)获得(v2)
    则再把(a o b)连接边权为(v1)的边,(b o a)连接边权为(v2)的边。
    这两条边能选且只能选一条。选了以后获得权值的收益。
    且在新图中,每个点的入度最多为1。

    题目要求收益最大。
    考虑对树/基环树分类讨论。
    一棵树

  • 相关阅读:
    SDNU 1219.sign up problem
    SDNU 1232.A*B Problem(高精度)
    Go操作MySQL
    BootStrap jQuery 在线cdn
    Go语言标准库之http/template
    Go语言基础之net/http
    Go语言基础之网络编程
    Go语言基础之单元测试
    Go语言基础之rand(随机数)包
    Go语言基础之并发
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13858571.html
Copyright © 2011-2022 走看看