zoukankan      html  css  js  c++  java
  • ZOJ3967 : Card Game

    比赛的时候因为卡内存,在抠内存的时候改错了,导致赛内没有AC,赛后发现数组开的很小都可以AC。

    分析题意我们发现,这题需要求出所有存在的直线形成的上凸壳,那么查询$[L,R]$时在凸壳上二分导数,找到最大值即可。

    因为有删除操作,故离线求出每条直线存在的时间区间,在时间线段树上打标记,那么这样会转化成$O(nlog n)$次插入。

    那么现在需要维护一个数据结构,支持插入直线,询问单点最值,这显然可以使用李超线段树。

    沿着时间线段树进行dfs,用一个栈按时间记录所有修改,那么可以很方便地实现李超线段树的还原。

    时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    #include<algorithm>
    #include<stack>
    #include<map>
    using namespace std;
    typedef pair<int,int>P;
    typedef long long ll;
    const int N=100010,M=1500000,E=200010;
    const int eps=5;
    const int inf=1000000000;
    const ll offset=2000000000LL;
    const ll infll=1LL<<62;
    int Case,n,m,i,op,x,y;
    int st[N],en[N],cur;
    int cq,que[N][2],g[N],nxt[N];
    ll ans[N];
    int G[131111],V[M],NXT[M],ED;
    map<P,stack<int> >idx;
    
    int root,tot,l[E],r[E],val[E];
    
    int pool[E][2],cpool;
    
    struct LINE{
    	int k,b;
    }a[N];
    
    inline ll cal(int x,int p){return 1LL*a[x].k*p+a[x].b;}
    
    inline void addedge(int x,int y){
    	nxt[y]=g[x];g[x]=y;
    }
    void build(int x,int a,int b){
    	G[x]=0;
    	if(a==b)return;
    	int mid=(a+b)>>1;
    	build(x<<1,a,mid);
    	build(x<<1|1,mid+1,b);
    }
    void tag(int x,int a,int b,int c,int d,int p){
    	if(c<=a&&b<=d){
    		V[++ED]=p;
    		NXT[ED]=G[x];
    		G[x]=ED;
    		return;
    	}
    	int mid=(a+b)>>1;
    	if(c<=mid)tag(x<<1,a,mid,c,d,p);
    	if(d>mid)tag(x<<1|1,mid+1,b,c,d,p);
    }
    void ins(int&x,int a,int b,int p,int f){
    	if(!val[x]){
    		x=++tot;
    		l[x]=r[x]=0;
    		pool[++cpool][0]=x;
    		pool[cpool][1]=-f;
    		val[x]=p;
    		return;
    	}
    	if(cal(p,a)<cal(val[x],a)&&cal(p,b)<cal(val[x],b)){
    		pool[++cpool][0]=x;
    		pool[cpool][1]=val[x];
    		val[x]=p;
    		return;
    	}
    	if(cal(p,a)>=cal(val[x],a)&&cal(p,b)>=cal(val[x],b)){
    		return;
    	}
    	if(a==b)return;
    	ll mid=((offset+a+b)>>1)-inf;
    	ins(l[x],a,mid,p,x);
    	ins(r[x],mid+1,b,p,x);
    }
    inline void umin(ll&a,ll b){if(a>b)a=b;}
    inline void umax(ll&a,ll b){if(a<b)a=b;}
    ll TMP;
    void ask(int x,int a,int b,int c){
    	if(!val[x])return;
    	umin(TMP,cal(val[x],c));
    	if(a==b)return;
    	ll mid=((offset+a+b)>>1)-inf;
    	if(c<=mid)ask(l[x],a,mid,c);else ask(r[x],mid+1,b,c);
    }
    inline void retrace(int pos){
    	while(cpool>pos){
    		int x=pool[cpool][0],y=pool[cpool--][1];
    		val[x]=y;
    		if(y<=0){
    		  tot--;
    		  if(y<0){
    		    if(l[-y]==x)l[-y]=0;
    		    if(r[-y]==x)r[-y]=0;
    		  }
    		}
    	}
    }
    inline ll query(int L,int R){
    	//find max t that f(t)>f(t-1)
    	int o=L++;
    	while(L<=R){
    		ll mid=((offset+L+R)>>1)-inf;
    		TMP=infll;
    		ask(root,-inf,inf,mid);
    		ll u=TMP;
    		TMP=infll;
    		ask(root,-inf,inf,mid-1);
    		if(u>TMP)L=(o=mid)+1;else R=mid-1;
    	}
    	TMP=infll;
    	ask(root,-inf,inf,o);
    	return TMP;
    }
    void dfs(int x,int a,int b){
    	int pos=cpool;
    	for(int i=G[x];i;i=NXT[i]){
    		ins(root,-inf,inf,V[i],0);
    	}
    	if(a==b){
    		for(int i=g[a];i;i=nxt[i]){
    			ans[i]=query(que[i][0],que[i][1]);
    		}
    		retrace(pos);
    		return;
    	}
    	int mid=(a+b)>>1;
    	dfs(x<<1,a,mid);
    	dfs(x<<1|1,mid+1,b);
    	retrace(pos);
    }
    int main(){
    	scanf("%d",&Case);
    	while(Case--){
    		scanf("%d%d",&n,&m);
    		cur=1;
    		for(i=1;i<=n;i++){
    			scanf("%d%d",&a[i].k,&a[i].b);
    			idx[P(a[i].k,a[i].b)].push(i);
    			st[i]=1;
    		}
    		for(i=1;i<=m;i++){
    			scanf("%d%d%d",&op,&x,&y);
    			if(op==0){
    				cq++;
    				que[cq][0]=x;
    				que[cq][1]=y;
    				addedge(cur,cq);
    			}
    			if(op==1){
    				cur++;
    				a[++n].k=x;
    				a[n].b=y;
    				st[n]=cur;
    				idx[P(x,y)].push(n);
    			}
    			if(op==2){
    				int z=idx[P(x,y)].top();
    				idx[P(x,y)].pop();
    				en[z]=cur++;
    			}
    		}
    		for(i=1;i<=n;i++)if(!en[i])en[i]=cur;
    		build(1,1,cur);
    		for(i=1;i<=n;i++)tag(1,1,cur,st[i],en[i],i);
    		dfs(1,1,cur);
    		for(i=1;i<=cq;i++)printf("%lld
    ",ans[i]);
    		
    		cq=0;
    		for(i=1;i<=n;i++)en[i]=0;
    		for(i=1;i<=cur;i++)g[i]=0;
    		ED=0;
    		idx.clear();
    	}
    }
    

      

  • 相关阅读:
    小账本软件设计之数据库设计模式构建
    基于JMeter的Quick Easy FTP Server性能测试
    构建之法 -源代码管理
    小账本APP——软件项目风险管理及解决办法案例
    基于python的Splash基本使用和负载均衡配置
    MQ初窥门径【面试必看的Kafka和RocketMQ存储区别】
    Apollo源码搭建调试看一文就够
    log4j2异步日志解读(二)AsyncLogger
    Disruptor源码解读
    高性能队列disruptor为什么这么快?
  • 原文地址:https://www.cnblogs.com/clrs97/p/6750510.html
Copyright © 2011-2022 走看看