COGS 1834. [国家集训队2011]采矿

人类互相伤害的典型题目

首先显然两个分组背包是可以合并的

所以我们可以用线段树维护一段区间的背包解

于是就变成了树剖了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
const int N=20000+5;
const int M=50+5;
int m;
struct dp_node{
	int f[M];
	void clr(){mmt(f,0);}
	dp_node(){clr();}
	void print(){
		rep(i,1,m)printf("%d ",f[i]);putchar('\n');
	}
};
dp_node operator + (dp_node a,dp_node b){
	static dp_node c;c.clr();
	rep(i,0,m)rep(j,0,i)c.f[i]=max(c.f[i],a.f[j]+b.f[i-j]);
	rep(i,1,m)c.f[i]=max(c.f[i],c.f[i-1]);
	return c;
}
dp_node operator * (dp_node a,dp_node b){
	static dp_node c;c.clr();
	rep(i,0,m)c.f[i]=max(a.f[i],b.f[i]);
	return c;
}
struct Node{
	int l,r;
	dp_node f,g;
}tr[N<<2];
#define lc o<<1
#define rc o<<1|1
void pushup(int o){
	tr[o].g=tr[lc].g*tr[rc].g;
	tr[o].f=tr[lc].f+tr[rc].f;
}
dp_node query(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r;
	if(a<=l&&r<=b)return tr[o].f;
	dp_node f;
	int mid=l+r>>1;
	if(a<=mid)f=f+query(lc,a,b);
	if(mid<b)f=f+query(rc,a,b);
	return f;
}
dp_node ask(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r;
	if(a<=l&&r<=b)return tr[o].g;
	dp_node g;
	int mid=l+r>>1;
	if(a<=mid)g=g*ask(lc,a,b);
	if(mid<b)g=g*ask(rc,a,b);
	return g;
}
int table[N][M];
void build(int o,int l,int r){
	tr[o].l=l;tr[o].r=r;
	if(l==r){
		rep(i,1,m)tr[o].f.f[i]=tr[o].g.f[i]=table[l][i];
	}else{
		int mid=l+r>>1;
		build(lc,l,mid);build(rc,mid+1,r);
		pushup(o);
	}
}
int A,B,Q;
int getint(){
	A=((A^B)+(B>>16)+(B<<16))&0x7fffffff;
	B=((A^B)+(A>>16)+(A<<16))&0x7fffffff;
	return (A^B)%Q;
}
void update(int o,int p){
	int l=tr[o].l,r=tr[o].r;
	if(l==r){
		rep(i,1,m)tr[o].f.f[i]=getint();
		sort(tr[o].f.f+1,tr[o].f.f+1+m);
		rep(i,1,m)tr[o].g.f[i]=tr[o].f.f[i];
	}else{
		int mid=l+r>>1;
		if(p<=mid)update(lc,p);
		else update(rc,p);
		pushup(o);
	}
}
struct Edge{int to,next;}e[N<<1];
int head[N],cnt;
void ins(int u,int v){e[++cnt]=(Edge){v,head[u]};head[u]=cnt;}
void insert(int u,int v){ins(u,v);ins(v,u);}
int fa[N],top[N],st[N],son[N],siz[N],dep[N],sz,ed[N];
void dfs(int u){
	son[u]=0;siz[u]=1;
	tra(i,u){
		int v=e[i].to;if(v==fa[u])continue;
		fa[v]=u;dep[v]=dep[u]+1;
		dfs(v);
		siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs(int u,int tp){
	top[u]=tp;st[u]=++sz;
	if(son[u])dfs(son[u],tp);
	tra(i,u){
		int v=e[i].to;
	 	if(v!=fa[u]&&v!=son[u])dfs(v,v);
	}
	ed[u]=sz;
}
dp_node query(int u,int v){
	dp_node ans;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		ans=ans*ask(1,st[top[u]],st[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	return ans*ask(1,st[u],st[v]);
}
int ask(int u,int v){
	dp_node f=query(1,st[u],ed[u]);
	if(u==v)return f.f[m];
	else{
		dp_node g=query(fa[u],v);
		g=g+f;
		return g.f[m];
	}
}
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int n;scanf("%d%d%d%d%d",&n,&m,&A,&B,&Q);
	rep(i,2,n){int j;scanf("%d",&j);insert(i,j);}
	dfs(1);dfs(1,1);
	rep(i,1,n){
		rep(j,1,m)table[st[i]][j]=getint();
		sort(table[st[i]]+1,table[st[i]]+m+1);
	}
	build(1,1,n);
	int c;scanf("%d",&c);
	while(c--){
		int op,u,v;scanf("%d",&op);
		if(op==0){
			scanf("%d",&u);
			update(1,st[u]);
		}else{
			scanf("%d%d",&u,&v);
			printf("%d\n",ask(u,v));
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将代码修改为cot平滑的方法: 1. 首先,需要使用边界角的cot权重计算每个顶点的权重。 2. 然后,使用cot权重对每个顶点的邻域点进行加权计算,得到平滑后的坐标。 3. 最后,根据平滑后的坐标更新每个顶点的位置。 修改后的代码如下: float smooth() { float err = -1; cogs.clear(); v_end = mesh.vertices_end(); //cot平滑 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) { cog[0] = cog[1] = cog[2] = weight_sum = 0.0; for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { double cot_weight = 0.0; MyMesh::HalfedgeHandle heh = mesh.find_halfedge(*v_it, *vv_it); if (!mesh.is_boundary(heh)) { MyMesh::HalfedgeHandle prev_heh = mesh.prev_halfedge_handle(heh); MyMesh::HalfedgeHandle next_heh = mesh.next_halfedge_handle(heh); MyMesh::VertexHandle prev_vh = mesh.to_vertex_handle(prev_heh); MyMesh::VertexHandle next_vh = mesh.to_vertex_handle(next_heh); MyMesh::Point prev_p = mesh.point(prev_vh); MyMesh::Point curr_p = mesh.point(*v_it); MyMesh::Point next_p = mesh.point(next_vh); double cot_alpha = cot(prev_p - curr_p, next_p - curr_p); double cot_beta = cot(curr_p - prev_p, next_p - prev_p); cot_weight = cot_alpha + cot_beta; } cog += cot_weight * mesh.point(*vv_it); weight_sum += cot_weight; } cogs.push_back(cog / weight_sum); } for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end; ++v_it, ++cog_it) { if (!mesh.is_boundary(*v_it)) { MyMesh::Point p = mesh.point(*v_it); err = max(err, (p - *cog_it).norm()); mesh.set_point(*v_it, *cog_it); } } return err; } 其中cot函数的定义如下: double cot(MyMesh::Point a, MyMesh::Point b) { return dot(a, b) / cross(a, b).norm(); } 注意,这里使用的是边界角的cot权重,因此在计算cot权重时需要判断当前边是否为边界。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值