• CF::Gym 100739E


    CF::Gym题目页面传送门

    给定(n)个整数坐标((x_i,y_i))。你需要支持(2)(q)次操作:

    1. ( exttt0 a b c):令(x_a=b,y_a=c)
    2. ( exttt1 a b):一个人从((a,b))出发,每秒可以向八连通的格子走,要从对(forall iin[1,n],(x_i,y_i))完成一个来回,每次回到家要休息(2mathrm s)(共(n-1)次),求总时间。

    强制在线。

    (n,qinleft[0,10^5 ight])(mathrm{TL}=1mathrm s,mathrm{ML}=64mathrm{MB})

    不难发现,对于操作( exttt1)答案就是(sumlimits_{i=1}^n2max(|x_i-a|,|y_i-b|)+2(n-1)),要求的就是前面那个(sum),即((a,b))(n)个点的切比雪夫距离之和。

    注意到,这里有绝对值,本身就需要零点分段,两个绝对值外面再套个(max),又要分类讨论,这岂不是很烦?这里需要用到一个非常经典的套路:切比雪夫转曼哈顿。

    稍微说一下他们的互换吧,毕竟是第一次用。记得上hb新生班的时候,有一个同学不会abs函数,于是就把abs(x)写成max(x,-x),hm夸他很聪明。在这里,我们也可以把曼哈顿距离中的绝对值拆成(max),最终再合成绝对值:

    [egin{aligned}&|x_1-x_2|+|y_1-y_2|\=&max(x_1-x_2,x_2-x_1)+max(y_1-y_2,y_2-y_1)\=&max(x_1-x_2+y_1-y_2,x_1-x_2+y_2-y_1,x_2-x_1+y_1-y_2,x_2-x_1+y_2-y_1)\=&max((x_1+y_1)-(x_2+y_2),(x_1-y_1)-(x_2-y_2),(x_2-y_2)-(x_1-y_1),(x_2+y_2)-(x_1+y_1))\=&max(max((x_1+y_1)-(x_2+y_2),(x_2+y_2)-(x_1+y_1)),max((x_1-y_1)-(x_2-y_2),(x_2-y_2)-(x_1-y_1)))\=&max(|(x_1+y_1)-(x_2+y_2)|,|(x_1-y_1)-(x_2-y_2)|)end{aligned} ]

    于是不难发现,((x_1,y_1),(x_2,y_2))的曼哈顿距离等于((x_1+y_1,x_1-y_1),(x_2+y_2,x_2-y_2))的切比雪夫距离。反过来?我们设((x_1,y_1),(x_2,y_2))的切比雪夫距离等于(left(x_1',y_1' ight),left(x_2',y_2' ight))的曼哈顿距离,不难得到四元一次方程组

    [egin{cases}x_1'+y_1'=x_1\x_1'-y_1'=y_1\x_2'+y_2'=x_2\x_2'-y_2'=y_2end{cases} ]

    解得

    [egin{cases}x_1'=dfrac{x_1+y_1}2\y_1'=dfrac{x_1-y_1}2\x_2'=dfrac{x_2+y_2}2\y_2'=dfrac{x_2-y_2}2end{cases} ]

    于是,((x_1,y_1),(x_2,y_2))的切比雪夫距离等于(left(dfrac{x_1+y_1}2,dfrac{x_1-y_1}2 ight),left(dfrac{x_2+y_2}2,dfrac{x_2-y_2}2 ight))的曼哈顿距离。

    回到本题,把切比雪夫距离的坐标转成曼哈顿距离的坐标(好了,下面讨论的坐标全是曼哈顿距离的坐标了)。现在(max)没有了,只剩下(+)号。不难想到将两个绝对值零点分段,分成以((a,b))为原点的四个象限,然后就可以二维数点。由于强制在线,所以只能(mathrm O!left(qlog^2v ight)),其中(v)是值域大小。虽然时间上说得过去,但空间毫无疑问会爆炸。

    不过,二维数点个*啊?由于变成了(+)号,所以左边的绝对值和右边的绝对值可以分别求和,最终加到一起。这样的话,两个零点分段就是独立的,最多只有一重,也就是将整个平面分成两个半平面(而不是四个)。这样就可以一维数点了/cy

    BIT?线段树?不行,因为强制在线不能离散化,基于值域建不了。动态开点线段树?抱歉,会炸空间。只剩一个选择了,就是平衡树(这里使用fhq-Treap)。维护子树内的坐标之和与实际存在的点的个数;计算答案时在平衡树内询问某个半平面内的信息,另一个半平面内的信息就用总坐标和与总点数((n))减去;一次单点增加/减少就插入一个节点,权值是对应要增加/减少的值(的相反数)。时间复杂度(mathrm O(qlog n)),空间复杂度(mathrm O(n))

    有个坑点,就是每次的lasans输出完之后要尛一下base,不然下次解压的时候直接乘会爆long long。要不是hsc神仙提醒我,我就不能1A了/qq

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define mp make_pair
    #define X first
    #define Y second
    mt19937 rng(20060617);
    const int N=100000;
    int n,qu,base;
    int x[N+1],y[N+1];
    struct fhq_treap{
    	int sz,root;
    	struct node{unsigned key;int lson,rson,sz,v1/*键值*/,v2/*坐标*/,v3/*实际点数*/,sum2/*字数内坐标和*/,sum3/*字数内实际点数*/;}nd[3*N+1];
    	#define key(p) nd[p].key
    	#define lson(p) nd[p].lson
    	#define rson(p) nd[p].rson
    	#define sz(p) nd[p].sz
    	#define v1(p) nd[p].v1
    	#define v2(p) nd[p].v2
    	#define v3(p) nd[p].v3
    	#define sum2(p) nd[p].sum2
    	#define sum3(p) nd[p].sum3
    	void init(){//初始化,一开始为空 
    		sz=root=0; 
    		nd[0]=node({0,0,0,0,0,0,0,0,0});
    	}
    	void sprup(int p){
    		sz(p)=sz(lson(p))+1+sz(rson(p));
    		sum2(p)=sum2(lson(p))+v2(p)+sum2(rson(p));
    		sum3(p)=sum3(lson(p))+v3(p)+sum3(rson(p));
    	}
    	int nwnd(int v1,int v2,int v3){return nd[++sz]=node({rng(),0,0,1,v1,v2,v3,v2,v3}),sz;}
    	pair<int,int> split(int x,int p=-1){~p||(p=root);
    		if(!x)return mp(0,p);
    		pair<int,int> sp;
    		if(x<=sz(lson(p)))return sp=split(x,lson(p)),lson(p)=sp.Y,sprup(p),mp(sp.X,p);
    		return sp=split(x-1-sz(lson(p)),rson(p)),rson(p)=sp.X,sprup(p),mp(p,sp.Y);
    	}
    	int mrg(int p,int q){
    		if(!p||!q)return p|q;
    		if(key(p)<key(q))return rson(p)=mrg(rson(p),q),sprup(p),p;
    		return lson(q)=mrg(p,lson(q)),sprup(q),q;
    	}
    	int lss(int v,int p=-1){~p||(p=root); 
    		if(!p)return 0;
    		if(v1(p)<v)return sz(lson(p))+1+lss(v,rson(p));
    		return lss(v,lson(p));
    	}
    	void add(int x,int v2,int v3){//单点增加 
    		pair<int,int> sp=split(lss(x));
    		root=mrg(mrg(sp.X,nwnd(x,v2,v3)),sp.Y);
    	}
    	pair<int,int> suM(int x){//后缀查询 
    //		cout<<sz<<"
    ";
    		pair<int,int> sp=split(lss(x));
    		pair<int,int> res=mp(sum2(sp.Y),sum3(sp.Y));
    		return root=mrg(sp.X,sp.Y),res;
    	}
    }trp_x,trp_y;//各维护两边绝对值之和的平衡树 
    signed main(){
    	cin>>n>>qu>>base;
    	int tot_x=0,tot_y=0;
    	for(int i=1;i<=n;i++){
    		scanf("%lld%lld",x+i,y+i);
    		int tmp=x[i];
    		x[i]+=y[i];y[i]=tmp-y[i];//转距离 
    		tot_x+=x[i];tot_y+=y[i]; 
    //		cout<<x[i]<<" "<<y[i]<<"
    ";
    	}
    	trp_x.init();trp_y.init();//平衡树初始化 
    	for(int i=1;i<=n;i++)trp_x.add(x[i],x[i],1),trp_y.add(y[i],y[i],1);//将初始的n个节点插入 
    	int lasans=0;
    	while(qu--){
    		int tp,a,b,c,d,e;
    		scanf("%lld%lld%lld%lld%lld",&tp,&a,&b,&c,&d);
    		if(tp==0){
    			scanf("%lld",&e);
    			trp_x.add(x[a],-x[a],-1);trp_y.add(y[a],-y[a],-1);//单点减少 
    			tot_x-=x[a];tot_y-=y[a];
    			x[a]=(b*lasans+c)%base;y[a]=(d*lasans+e)%base;
    			int tmp=x[a];
    			x[a]+=y[a];y[a]=tmp-y[a];//转距离 
    			trp_x.add(x[a],x[a],1);trp_y.add(y[a],y[a],1);//单点增加 
    			tot_x+=x[a];tot_y+=y[a];
    		}
    		else{
    			int x=(a*lasans+b)%base,y=(c*lasans+d)%base;
    //			cout<<x<<" "<<y<<"
    ";
    			int tmp=x;
    			x+=y;y=tmp-y;//转距离 
    //			cout<<x<<" "<<y<<"
    ";
    			pair<int,int> res1=trp_x.suM(x),res2=trp_y.suM(y);//询问某个半平面内的信息 
    //			printf("res1=(%lld,%lld) res2=(%lld,%lld)
    ",res1.X,res1.Y,res2.X,res2.Y);
    			lasans=res1.X-res1.Y*x+(n-res1.Y)*x-(tot_x-res1.X)+res2.X-res2.Y*y+(n-res2.Y)*y-(tot_y-res2.X);
    			lasans+=n-1<<1;//计算答案 
    			printf("%lld
    ",lasans);
    			lasans%=base;//%%%hsctxdy
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何删除或更改已经释放的TR
    [问题解决]调用BAPI_ACC_DOCUMENT_POST时报错“被合并的公司 XXXX 和 XXXX 是不同的”
    如何判断暂存采购订单(EKKO-MEMORY)
    Django之HttpRequest和HttpReponse
    Django之模板继承
    Django之模板语法
    python库之selectors
    python库之threading
    JDBC学习笔记(9)——DBUtils的使用
    XML学习笔记(1)--XML概述
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/CF-Gym-100739E.html
Copyright © 2020-2023  润新知