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();
    	}
    }
    

      

  • 相关阅读:
    Educational Codeforces Round 10 C. Foe Pairs 水题
    Educational Codeforces Round 10 B. z-sort 构造
    CDOJ 1048 Bob's vector 三分
    Educational Codeforces Round 10 A. Gabriel and Caterpillar 模拟
    第14届电子科大初赛民间盗版部分题目题解
    HDU 5654 xiaoxin and his watermelon candy 离线树状数组 区间不同数的个数
    HDU 5653 Bomber Man wants to bomb an Array. dp
    HDU 5652 India and China Origins 二分+并查集
    HDU 5651 xiaoxin juju needs help 数学
    HDU 5650 so easy 数学
  • 原文地址:https://www.cnblogs.com/clrs97/p/6750510.html
Copyright © 2011-2022 走看看