洛谷P3345 [ZJOI2015]幻想乡战略游戏

xiaoxiao2021-02-27  228

题目描述

傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。

在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。

在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv*dist(u,v)的金钱来补给这些军队。

由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。

因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。

但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。

输入输出格式

输入格式: 第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。 接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。 接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。数据保证任何时刻每个点上的军队数量都是非负的。

输出格式: 对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。

输入输出样例

输入样例#1: 10 5 1 2 1 2 3 1 2 4 1 1 5 1 2 6 1 2 7 1 5 8 1 7 9 1 1 10 1 3 1 2 1 8 1 3 1 4 1 输出样例#1: 0 1 4 5 6 说明

对于所有数据,1<=c<=1000, 0<=|e|<=1000, n<=105, Q<=105

#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define inf 1000000000 #define mod 1000000007 using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } ll ans,tot; int n,m,cnt,id,rt=1; int head[100005]; int fa[100005],size[100005],dep[100005],d[100005],bl[100005]; int pos[100005]; int sum[400005]; struct edge { int to,next,v; } e[200005]; void insert(int u,int v,int w) { e[++cnt]=(edge) { v,head[u],w }; head[u]=cnt; e[++cnt]=(edge) { u,head[v],w }; head[v]=cnt; } void Build(int k,int l,int r,int pos,int val) { if(l==r) { sum[k]+=val; return; } int mid=(l+r)>>1; if(pos<=mid)Build(k<<1,l,mid,pos,val); else Build(k<<1|1,mid+1,r,pos,val); sum[k]=sum[k<<1]+sum[k<<1|1]; } int query(int k,int l,int r,int x,int y) { if(l==x&&y==r)return sum[k]; int mid=(l+r)>>1; int ans=0; if(x<=mid)ans+=query(k<<1,l,mid,x,min(y,mid)); if(y>mid)ans+=query(k<<1|1,mid+1,r,max(x,mid+1),y); return ans; } void dfs(int x) { size[x]=1; for(int i=head[x]; i; i=e[i].next) if(e[i].to!=fa[x]) { fa[e[i].to]=x; dep[e[i].to]=dep[x]+1; d[e[i].to]=d[x]+e[i].v; dfs(e[i].to); size[x]+=size[e[i].to]; } } void dfs2(int x,int cha) { pos[x]=++id; bl[x]=cha; int k=0; for(int i=head[x]; i; i=e[i].next) if(e[i].to!=fa[x]&&size[e[i].to]>size[k]) k=e[i].to; if(k)dfs2(k,cha); for(int i=head[x]; i; i=e[i].next) if(e[i].to!=fa[x]&&e[i].to!=k) dfs2(e[i].to,e[i].to); } int lca(int x,int y) { while(bl[x]!=bl[y]) if(dep[bl[x]]>dep[bl[y]])x=fa[bl[x]]; else y=fa[bl[y]]; return dep[x]<dep[y]?x:y; } int dis(int x,int y) { return d[x]+d[y]-2*d[lca(x,y)]; } ll cal(int x,int v) { int t1,t2; if(x==fa[rt]) { t1=query(1,1,n,pos[rt],pos[rt]+size[rt]-1); t2=tot-t1; } else { t2=query(1,1,n,pos[x],pos[x]+size[x]-1); t1=tot-t2; } return ans+(ll)(t1-t2)*v; } void move(int x) { ll mn=(ll)1e60,t; int id=0; for(int i=head[x]; i; i=e[i].next) { t=cal(e[i].to,e[i].v); if(t<mn)mn=t,id=e[i].to; } if(mn<ans) { rt=id; ans=mn; move(rt); } } int main() { n=read(); m=read(); for(int i=1; i<n; i++) { int u=read(),v=read(),w=read(); insert(u,v,w); } dfs(1); dfs2(1,1); while(m--) { int u=read(),e=read(); ans+=(ll)e*dis(u,rt); tot+=e; Build(1,1,n,pos[u],e); move(rt); printf("%lld\n",ans); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-10301.html

最新回复(0)