google codejam Round 1C 2013 The Great Wall

题意就不写了,小的input,就是个模拟。


大的可以把区间离散化,或者用线段树。


线段树每个区间记录一个low值,查询的时候,看当前节点和祖先节点low值最大的;更新时如果low变大了,记得更新祖先节点。


下面是代码:

#include <iostream>
#include <string.h>
#include <math.h>
#include <set>
#include <utility>
#define min(a,b) ((a) < (b) ? (a) : (b)) 
#define max(a,b) ((a) > (b) ? (a) : (b)) 
using namespace std;
const int N=101000001;
//const int N=100;
int minh;
int lp,rp;
struct node
{
	int low;
	//int l,r;
	node *pl,*pr,*pa;
}*root,*last;

void del(node *&r)
{
	if(r!=NULL)
	{
		del(r->pl);
		del(r->pr);
		delete r;
		r=NULL;
	}
}
void query(node* ro,int l,int r)
{
	if(!ro)
	{
		int t=0;
		ro=last;
		while(ro)
		{
			t=max(t,ro->low);
			ro=ro->pa;
		}
		minh=min(t,minh);
		return ;
	}
	last=ro;
	if(l==lp&&r==rp)
	{
		int t=0;
		while(ro)
		{
			t=max(t,ro->low);
			ro=ro->pa;
		}
		minh=min(t,minh);
		return ;
	}
	int m=(lp+rp)/2;
	if(r<=m)
	{
		int t=rp;
		rp=(lp+rp)/2;
		last=ro;
		query(ro->pl,l,r);
		rp=t;
	}
	else if(l>=m)
	{
		int t=lp;
		lp=(lp+rp)/2;
		last=ro;
		query(ro->pr,l,r);
		lp=t;
	}
	else
	{
		int t=rp;
		rp=(lp+rp)/2;
		last=ro;
		query(ro->pl,l,m);
		rp=t;
		t=lp;
		lp=(lp+rp)/2;
		last=ro;
		query(ro->pr,m,r);
		lp=t;
	}
}
void insert(node *&ro,int l,int r,int c)
{
	if(!ro)
	{
		ro=new node();
		ro->pl=NULL;
		ro->pr=NULL;
		ro->pa=last;
		//ro->l=lp;
		//ro->r=rp;
		if(last)ro->low=last->low;
		else ro->low=0;
	}
	if(l==lp&&r==rp)
	{
		if(ro->low<c)
		{
			ro->low=c;
			node *tro=ro;
			tro=tro->pa;
			while(tro&&tro->pl&&tro->pr)
			{
				int tm=min(tro->pl->low,tro->pr->low);
				if(tro->low>=tm)break;
				tro->low=tm;
				tro=tro->pa;
			}
		}
	}
	else
	{
		int m=(lp+rp)/2;
		if(l<m)
		{
			int t=rp;
			rp=(lp+rp)/2;
			last=ro;
			insert(ro->pl,l,min(r,m),c);
			rp=t;
		}
		if(r>m)
		{
			int t=lp;
			lp=(lp+rp)/2;
			last=ro;
			insert(ro->pr,max(l,m),r,c);
			lp=t;
		}
	}
}
//void disp(node* r,int ma)
//{
//	if(!r)return;
//	if(r->pl==NULL&&r->pr==NULL)
//	{
//		printf("%d-%d %d\n",r->l,r->r,max(r->low,ma));
//	}
//	else
//	{
//		ma=max(ma,r->low);
//		disp(r->pl,ma);
//		disp(r->pr,ma);
//	}
//}
struct tri
{
	int d,n,w,e,s,dd,dp,ds;
	tri()
	{
		scanf("%d%d%d%d%d%d%d%d",&d,&n,&w,&e,&s,&dd,&dp,&ds);
	}
	bool att(int ad)
	{
		if(ad<d)return 0;
		if((ad-d)%dd==0)
		{
			int time=(ad-d)/dd;
			if(time>=n)return 0;
			minh=N;
			query(root,w+time*dp,e+time*dp);
			if(minh<s+time*ds)
			{
				//int pthis=0;
				//while(tt[pthis]!=this)pthis++;
				//printf("t %d d %d h %d ah %d %d-%d\n",pthis,ad,minh,s+time*ds,w+time*dp,e+time*dp);
				return 1;
			}
		}
		return 0;
	}
	void rep(int ad)
	{
		if(ad<d)return;
		if((ad-d)%dd==0)
		{
			int time=(ad-d)/dd;
			if(time>=n)return ;
			insert(root,w+time*dp,e+time*dp,s+time*ds);
			//disp(root,0);
		}
	}
}*tt[1005];

int main()
{
	freopen("C-large-practice.in","r",stdin);
	freopen("out.txt","w",stdout);
	int cas;
	int ki,i,j,nt,sum;
	scanf("%d",&cas);
	set<int>::iterator it;
	lp=-N;
	rp=N;
	for(ki=1;ki<=cas;ki++)
	{
		root=last=NULL;
		insert(root,-N,N,0);
		sum=0;
		set<int> ad;
		printf("Case #%d: ",ki);
		scanf("%d",&nt);
		for(i=0;i<nt;i++)
		{
			tt[i]=new tri();
			for(j=0;j<tt[i]->n;j++)
				ad.insert(tt[i]->d+j*tt[i]->dd);
		}
		for(it=ad.begin();it!=ad.end();it++)
		{
			//printf("day:%d\n",*it);
			for(i=0;i<nt;i++)
				sum+=tt[i]->att(*it);
			for(i=0;i<nt;i++)
				tt[i]->rep(*it);
		}
		printf("%d\n",sum);
		del(root);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值