树状数组+扫描线部分分做法求条
查看原帖
树状数组+扫描线部分分做法求条
1385606
Yun_Mo_s5_013楼主2025/7/1 16:27

只得到了高贵的8pts

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100010
#define lowbit(x) x&(-x)

int c,T;
int n,m,K,d,x,y,v[N];
int X[N],Y[N];//此处X,Y分别记录每个任务区间的左右端点
int b[N],cnt;//离散化数组
struct que{
	int y,v;
};
vector<que> q[N];
int dp[N];

/*树状数组*/
int Bit[N];
void add(int x,int k){
	while(x<=cnt){Bit[x]+=k; x+=lowbit(x);}
}

int get(int x){
	int res=0;
	while(x>0){res+=Bit[x]; x-=lowbit(x);}
	return res;
}

int ask(int l,int r){return get(r)-get(l-1);}

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>c>>T;
	while(T--){
		for(int i=1;i<=cnt;i++) {
			q[i].clear();Bit[i]=0;dp[i]=0;b[i]=0;v[i]=0;X[i]=Y[i]=0;}
		cnt=0;
		cin>>n>>m>>K>>d;
		for(int i=1;i<=m;i++){
			cin>>x>>y>>v[i];
			X[i]=x-y+1; Y[i]=x;
			b[++cnt]=x;
			b[++cnt]=x-y+1;
		}
		//离散化
		sort(b+1,b+cnt+1);
		cnt=unique(b+1,b+cnt+1)-b-1;
		for(int i=1;i<=m;i++){
			X[i]=lower_bound(b+1,b+cnt+1,X[i])-b;
			Y[i]=lower_bound(b+1,b+cnt+1,Y[i])-b;
			q[Y[i]].push_back((que){X[i],v[i]});
		}
		/*暴力dp*/
		dp[0]=0;
		for(int i=1;i<=cnt;i++){//枚举天数
			//把枚举到的挑战加入树状数组,便于查询
			for(auto it:q[i]){
				add(it.y,it.v);
			}
			for(int j=i;j>=1&&(b[i]-b[j]+1<=K);j--){
				//枚举j代表从j到i这段时间跑步。
				/*转移从j-2来,因为连续跑步天数不超过K,所以我们枚举到j则第
				j-1天一定不跑(否则将存在一个长度大于K的大区间)则从j-2转移
				注意离散化之后需要注意相邻两个值是否相差1,差1则选取j-2,否则
				直接选取j-1*/
				int pos=(b[j-1]!=b[j]-1)?j-1:j-2;
				int tmp=(pos<=0)?0:dp[pos];
				//j-2可能越界,但越界了也能转移,所以需要特殊处理
				dp[i]=max(dp[i],tmp+ask(j,i)-d*(i-j+1));
			}
			dp[i]=max(dp[i],dp[i-1]);//今天不跑,直接继承
		}
		cout<<dp[cnt]<<'\n';
	}
	return 0;
}
2025/7/1 16:27
加载中...