1. 程式人生 > >洛谷P2190 小Z的車廂

洛谷P2190 小Z的車廂

題目描述

小Z的家鄉有一列在環形鐵軌上行駛的火車,共停靠 n 個站(1 號站到 n 號站順時針排列)。

眾所周知,春運是一件非常可怕的事情。不幸的是,小Z是鐵路公司的員工,現在他收到了 m 條除夕凌晨的訂票申請,每個申請 (x,y,z) 表示有 z 個人要從 x 號站順時針坐到 y 號站,同時,當火車停靠到x號站時,所有要在x站上車的人都會上車,所有要在x號站下車的人都會下車。

由於始發站不確定,現在小Z想知道至少需要分配給這列火車多少節車廂(每節車廂可容納 36 人)才能順利完成該鐵路運輸,希望你幫幫他。

輸入輸出格式

輸入格式:

 

第一行包含兩個整數 n,m。

接下來 m 行,每行包含三個整數 x,y,z。

 

輸出格式:

 

第一行包含一個整數,表示至少需要分配給這列火車的車廂數。

 

輸入輸出樣例

輸入樣例#1:

3 2
1 2 36
2 3 36

輸出樣例#1:

1

輸入樣例#2:

4 2
1 2 36
4 3 36

輸出樣例#2:

2

洛谷說這是一道模擬題,不過我覺得這是在坑人

我想到了三個解法(題解上說的差分我不是很懂):

解法1

直接暴力模擬,時間O(NM)這個顯然是不行的

解法2

如果你很強,對演算法掌握的很好的話,就可以直接用險段樹做

利用lazy延遲修改,並且查詢最大值,比賽的時候一般不用

這樣很太複雜而且不容易除錯,但是不暴力

時間是O(mlogn+logn),不過常數和記憶體都很大

我雖然會不過不想打了

解法3

樹狀陣列+差分

這一題我們利用樹狀陣列來維護差分

1修改:

如果x<y

那麼我們就給點x +z(update(x,z))

給點y -z(update(y,-z))

如果x>y

就update(x,z),update(1,z),update(y,-z)

很好的處理首尾相接

最後

求出每一個數的字首和,找出最大的,處理一下就行了

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<string>
#include<set>
#include<ctime>
#define lowbit(x) x&(-x)
using namespace std;
inline int read(){
	int x=0,f=0;char s=getchar();
	while(!isdigit(s))f|=s=='-',s=getchar();
	while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
	return !f?x:-x;
}
inline void print(int x){
     if(x<0)putchar('-'),x=-x;
     if(x>9)print(x/10);
     putchar(x%10+'0');
}
const int N=1e6+20;
int n,m,a[N];
void update(int x,int t){//給點x加t 
	while(x<=n){
		a[x]+=t;
		x+=lowbit(x);
	}
}
int getsum(int x){//求點x的字首和 
	int sum=0;
	while(x>0){
		sum+=a[x];
		x-=lowbit(x);
	}
	return sum;
}
int main(){
	n=read();m=read();
	int x,y,z;
	for(int i=1;i<=m;i++){
		x=read();y=read();z=read();//差分修改 
		if(x<y)update(x,z),update(y,-z);
		else update(x,z),update(1,z),update(y,-z);
	}
	int maxx=0;
	for(int i=1;i<=n;i++)//求最大值 
		maxx=max(maxx,getsum(i));
	if(maxx%36==0)maxx/=36;
	else maxx=maxx/36+1;
	print(maxx);//輸出 
	return 0;
}