codeforces 286D Tourists

此题写得比较奇怪比较二逼。。。。

首先我们可以算出每个线段相对于出发点的出现时间(勉强听得懂吧。。。)

现在问题就变成给n条已知线段,询问射线[n,+oo)中线段的总长度。

基础的主席树啦。。。。

(好吧,似乎有跟好的算法。。)


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int Maxn=2000005, Maxm=100005;
int minx[Maxn],tip[Maxn],a[Maxn];
int L[Maxm],R[Maxm],ti[Maxm],T[Maxm*2];
int lef[Maxn*2],rig[Maxn*2],b[Maxn],c[Maxn];
int n,m,N,M,t,i,j,x,y,start;
LL sum1[Maxn*2],sum2[Maxn*2],f[Maxm*2],ans;
struct arr
{
	int l,r;
	bool operator <(const arr &a)const
	 { return (r<a.r || (r==a.r && l<a.l)); }
} G[Maxn];

void push(int p){
	if (tip[p*2+1]>tip[p] || tip[p*2+1]<0)
	  tip[p*2+1]=tip[p];
  if (tip[p*2+2]>tip[p] || tip[p*2+2]<0)
	  tip[p*2+2]=tip[p];
  minx[p*2+1]=min(minx[p*2+1],tip[p]);
	minx[p*2+2]=min(minx[p*2+2],tip[p]);
	tip[p]=-1;
}

void add(int p,int l,int r,int L,int R,int data){
	if (l>R || L>r) return;
	if (L<=l && R>=r){
		if (tip[p]>data || tip[p]<0)
	    tip[p]=data;
		minx[p]=min(minx[p],data);
		return;
	}
	if (tip[p]>=0) push(p);
	int mid=(l+r)>>1;
	add(p*2+1,l,mid,L,R,data);
	add(p*2+2,mid+1,r,L,R,data);
	minx[p]=min(minx[p*2+1],minx[p*2+2]);
}

void getit(int p,int l,int r){
	if (l==r){
		c[l]=minx[p];
		return;
	}
	if (tip[p]>=0) push(p);
	int mid=(l+r)>>1;
	getit(p*2+1,l,mid);
	getit(p*2+2,mid+1,r);
}

void work1(){
  for (i=1;i<=m;i++){
  	scanf("%d%d%d",&L[i],&R[i],&ti[i]);
  	R[i]--;
  	a[++M]=L[i]-1; a[++M]=L[i];
		a[++M]=R[i]; a[++M]=R[i]+1;
  }
  sort(a+1,a+M+1);
  M=unique(a+1,a+M+1)-a-1;
  memset(minx,127/2,sizeof(minx));
  memset(tip,-1,sizeof(tip));
  for (i=1;i<=m;i++){
  	L[i]=lower_bound(a+1,a+M+1,L[i])-a;
  	R[i]=lower_bound(a+1,a+M+1,R[i])-a;
  	add(0,1,M,L[i],R[i],ti[i]);
  }
  getit(0,1,M);
  for (i=1,N=t=0;i<=M;i=j){
  	for (j=i;c[j]==c[i]&&j<=M;j++);
  	if (c[i]>1000000000) continue;
  	G[++N].r=c[i]-a[i];
  	G[N].l=c[j-1]-a[j-1];
  	b[++t]=G[N].l;
  }
}

void ins(int p,int &q,int l,int r,int x){
	q=++start;
	lef[q]=lef[p]; rig[q]=rig[p];
	sum1[q]=sum1[p]+(LL)b[G[x].l]-1;
	sum2[q]=sum2[p]+1;
	if (l==r) return;
	int mid=(l+r)>>1;
	if (G[x].l<=mid) ins(lef[p],lef[q],l,mid,x);
	  else ins(rig[p],rig[q],mid+1,r,x);
}

void query(int p,int l,int r,int x){
	if (b[l]>x || p==0) return;
	if (b[r]<=x){
		ans+=sum2[p]*(LL)x-sum1[p];
		return;
	}
	int mid=(l+r)>>1;
	query(lef[p],l,mid,x);
	query(rig[p],mid+1,r,x);
}

int UPPER_BOUND(int x){
	int l=1, r=N;
	int mid, ret=0;
	while (l<=r){
		mid=(l+r)>>1;
		if (G[mid].r<=x) ret=mid, l=mid+1;
		  else r=mid-1;
	}
	return ret;
}

void work2(){
	sort(G+1,G+N+1);
	for (i=1;i<=N;i++)
		f[i]=f[i-1]+(LL)(G[i].r-G[i].l+1);
	sort(b+1,b+t+1);
	t=unique(b+1,b+t+1)-b-1;
	for (i=N;i>0;i--){
		G[i].l=lower_bound(b+1,b+t+1,G[i].l)-b;
		ins(T[i+1],T[i],1,t,i);
	}
	for (i=1;i<=n;i++){
		scanf("%d",&x);
		y=UPPER_BOUND(x);
		ans=f[y++];
		query(T[y],1,t,x);
		printf("%I64d\n",ans);
	}
}

int main(){
  //freopen("286D.in","r",stdin);
  //freopen("286D.out","w",stdout);
  scanf("%d%d",&n,&m);
  work1();
  work2();
  return 0;
}


你可能感兴趣的:(主席树)