Loading

LOJ 534 花团(线段树+dfs栈)

题意

https://loj.ac/problem/534

思路

又是复杂度错误的一题,\(O(n^2\log n)\) 能过 \(15000\)

虽然看起来强制在线,其实是一道假的在线题。首先按时间建立线段树,先序遍历整棵树,到叶子时进行更新并回答询问。

更新时将物品当做标记,打到线段树上 ,遍历到一个节点时,都在上面做背包,往儿子走时将背包数组拷贝下来,到另一个儿子重新拷贝一次,故背包个数和深度相同。

询问时由于已经维护好了目前的背包,可以直接询问。

这就是\(\text{dfs}\) 栈的思路,在 \(\text{dfs}\) 时维护一个栈,直接将父亲的信息拿下来使用。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
#define x first
#define y second
typedef long long LL;
using namespace std;
typedef pair<int,int> pii;
const int N=15005;
const int LOGN=18;
struct Knapsack
{
	LL dp[N];int n;
	LL &operator [](const int x){return dp[x];}
	void reset(int _n){n=_n;memset(dp,-1,sizeof(dp));dp[0]=0;}
	void Zo(int v,int w){DOR(i,n,v)if(dp[i-v]!=-1)dp[i]=max(dp[i],dp[i-v]+w);}
};
Knapsack Ks[LOGN];
vector<pii>A[N<<2];
int q,maxv,T;
LL lastans;

void update(int k,int L,int R,int v,int w,int l,int r)
{
	if(L<=l&&r<=R){A[k].push_back(pii(v,w));return;}
	int mid=(l+r)>>1;
	if(L<=mid)update(k<<1,L,R,v,w,l,mid);
	if(R>mid)update(k<<1|1,L,R,v,w,mid+1,r);
}
void solve(int k,int d,int l,int r)
{
	Ks[d]=Ks[d-1];
	FOR(i,0,(int)A[k].size()-1)Ks[d].Zo(A[k][i].x,A[k][i].y);
	if(l==r)
	{
		int op,v,w,e;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d%d",&v,&w,&e);
			v-=T*lastans,w-=T*lastans,e-=T*lastans;
			if(l+1<=e)update(1,l+1,e,v,w,1,q);
		}
		else
		{
			scanf("%d",&v);
			v-=T*lastans;
			if(Ks[d][v]==-1){puts("0 0");lastans=0;}
			else{printf("1 %lld\n",Ks[d][v]);lastans=(Ks[d][v]^1);}
		}
		return;
	}
	int mid=(l+r)>>1;
	solve(k<<1,d+1,l,mid);
	solve(k<<1|1,d+1,mid+1,r);
}

int main()
{
	scanf("%d%d%d",&q,&maxv,&T);
	Ks[0].reset(maxv);
	solve(1,1,1,q);
	return 0;
}
posted @ 2018-12-25 16:30  Paulliant  阅读(260)  评论(0编辑  收藏  举报